#!/bin/bash
# Gen6 to Gen7 port migration
# To modify this script to support new features/commands: 
#	1) add command that shows status of the feature into Gen7_Datacol function under chassis or switch level commands (if not already shown by existing commands)
#	2) add status command output parsing into Gen7_postprocess function, putting all port-specific info into the d[port,category] array.
#	3) add command CLI synthesis into Gen7_postprocess function under function doit()
#	4) Synthesis has several sections, first the per-port, then the per-port bitfields, then the feature specific.  Add your synthesis under appropriate section.

# set umask so that temporary files can be updated if run by either the admin or root user.
umask 0000

# Need to set path in case this is invoked as the admin user
export PATH=/fabos/link_bin:/bin:/usr/bin:/sbin:/usr/sbin:/fabos/link_abin:/fabos/link_sbin:/fabos/link_rbin

main(){
outputFile="Gen7_commands.sh"
 switch_enable="True" # Keep switch enabled
 while getopts 'pdfhc' c
 do
  case $c in
   f) outputFile=$2 ;; # Save output to the filename passed in
   p) Gen7_postprocess $2 ; script_over="True" ;;   # Do postprocess only for the saved file passed as argument
   c) Gen7_Datacol $switch_enable ; script_over="True" ;;  # Do only data collection to saved file
   d) set -x;; # Enable debugging
   h) echo "USAGE: PortCfgExtract [-hedc] [-p <file]"
      echo "         -h: Display help and usage"
      echo "         -c: Do only data collection to file /tmp/Gen6_save.txt"
      echo "         -p: Do only postprocessing on the earlier saved command file"
      echo "         -d: Turn on shell debugging"
      script_over="True" ;;
  esac
 done
 if [[ $script_over != "True" ]]; then
  Gen7_Datacol $switch_enable ; Gen7_postprocess /tmp/Gen6_save.txt
 fi }

Gen7_Datacol(){	# Saves port configurations for Gen6-Gen7 migration
 if [[ $1 != "True" ]];then
 com=switchcfgpersistentdisable;fosexec --fid all -cmd "$com" 2>&1|awk '/requires VF|not supported/{exit 1}1'||"$com"  # do com on non-VF or all VF
 fi
 (exe(){ if [[ $1 != 0 ]];then											#execute command on either VF or non-VF - $1 is fid, $2 is actual command
  cmd=$(echo "$3" fosexec --fid "$1" -cmd \""$2"\" "$4")				#$3 is pre-fosexec command, $4 is post-fosexec command
  eval "$cmd"|awk '/^-{51}$/{p++}!p';else eval "$3" "$2" "$4";fi; }		
 frmt(){ echo -e "\n## \""$2"\" on \""$1"\"";exe "$1" "$2" "$3" "$4"; }	# execute command and format output
 doit(){ echo -e "\n## Switch "$1										# switch level commands here
  frmt $1 "switchshow"
  frmt $1 "porttrunkarea --show all"
  frmt $1 "portaddress --show"
  frmt $1 "snmptraps --show port"
  frmt $1 "fapwwn --show all"
  frmt $1 "portcfgtdz --show '*'"
  frmt $1 "linkcost" "yes '' 2>/dev/null |" "|sed 's/Type <CR> to continue, Q<CR> to stop: //'"
  frmt $1 "portshow fciptunnel --detail"
  frmt $1 "portshow fcipcircuit --detail"; }
 fids=$(lscfg --show 2>/dev/null|awk -F: '/\(/{gsub(/\([0-9a-z/]*\)/,"");print $NF}')	# Get FIDs to doit on each VF or non-VF switch
 if [[ $fids ]];then for fid in $fids;do doit $fid;done;else doit 0;fi
 frmt 0 "slotshow -m"													# chassis level commands here - these will be done last since esp configshow needs switchshow index info
 frmt 0 "portshow tcl --detail"
 frmt 0 "configshow -all"												# Must be done after switchshow on all FIDs since requires index info
 frmt 0 "lscg 2>/dev/null|cmbg"											# rewritten lscfg - lscg and cmbg functions are at end of this script
 )|tee /tmp/Gen6_save.txt|awk 'FNR%100==0{printf "."}END{print ""}'; }  # print progress dots every 100 lines
 
 Gen7_postprocess(){ # Translates Saved port configurations into CLI commands for Gen6-Gen7 migration
 awk 'BEGIN{print "#!/bin/bash -x\n# Generated by '`basename "$0"`'"}	# -x will print the command before executing it
 BEGIN{print "printf \"Only execute this script after core blade replacement and reboot\\n\""}
 {gsub(/\r$/,"")}																	# In case file has windows EOLs, convert to unix EOL
  /^## /{m=0}																		# next section is coming - ends data collection on previous section
  /^## Switch /{fid=$3;fids[fid]=fid;next}											# Get fid, add to fids
  
  /^## "switchshow" /{m=1;s=p=0;next}												# Parse switchshow command output
  m==1&&/^switchWwn:/{d[fid,"switchwwn"]=$2}
  m==1&&/^switchDomain:/{d[fid,"switchdomain"]=$2}
  m==1&&/Default Switch: Yes/{deffid=fid}											# Set the default FID
  m==1&&/^=/{p++;next}																# found start of ports
  m==1&&/x Sl/{s++}																	# if director
  m==1&&$1=="E-Port"{next}															# ignore extra lines from EX ports
  m==1&&p==1&&NF{																	# if a valid port line
   if(s){tmp=substr($0,1,4);tmp1=substr($0,18);$0=substr($0,5);$0=sprintf("%s %6s %s",tmp,$1"/"$2,tmp1)}	# Consolidate Slot and Port into Slot/Port
   if($1+0==-1){next}																# ignore XISL ports with slot==-1
   if($0!~/[ \/]ge[0-9]/){															# Excluding ge ports
    b=substr($0,1,5);gsub(/ /,"",b);$0=substr($0,5);								# Separate out Index if it exists
    d[$1,"index"]=b;d[$1,"speed"]=$4;d[$1,"proto"]=$6;
    ports=ports $1" ";portindex[b]=$1;d[$1,"fid"]=fid}}
 
  /^## "porttrunkarea --show all" /{m=3;next}										# Parse porttrunkarea command output
  m==3&&$1~/^[0-9]/&&$(NF-1)~/^[0-9]/{
   if(d[$1"/"$2,"fid"]==fid){														# only set values if port is in current fid
   if($(NF-1) in ptab){ptae[$(NF-1)]=$2}else{ptab[$(NF-1)]=$1"/"$2}}}				# get beginning and end of port ranges
 
 /^## "configshow/{m=4;next}														# Parse configshow -all command output
  m==4&&/Fabric ID =/{if(!fid){cfid=0}else{cfid=$4+0}}								# Override cfid to 0 when non-VF,otherwise shows as 128
  m==4&& /\.port\.[0-9]+|\.[0-9]+:/ && !/np\.flow|ag\.port|^zone\./{				# for lines with .port.<port index> or .<port index>:
   split($0,atmp,":");
   tmp2=split(atmp[1],atmp2,".");
   if($0~/\.port\./){																# get lines with .port.
    if(d[portindex[atmp2[3]],"fid"]==cfid){d[portindex[atmp2[3]],atmp2[1] atmp2[4]]=atmp[2]}	# only set values if port is in current fid
   }else{
    if(d[portindex[atmp2[tmp2]],"fid"]==cfid){										# only set values if port is in current fid
     tmp="";for(j=1;j<tmp2;j++){tmp=tmp atmp2[j]}
     d[portindex[atmp2[tmp2]],tmp]=atmp[2]}}}
  m==4&&/^portCfg:/{																# Save portcfg bits under each port
   tmp3=split(substr($0,9),atmp,";")
   for(j=1;j<=tmp3;j++){
    tmp2=split(atmp[j],atmp2,",")
    if(d[portindex[atmp2[1]],"fid"]==cfid){											# only set values if port is in current fid
     d[portindex[atmp2[1]],"portcfg"]=substr(atmp[j],length(atmp2[1])+2)}}}
  m==4&&/^D_Dcc./{p1=index($0,":")	# Parse configshow output for DCC_POLICYs
   dccd[cfid,substr($0,7,p1-7)]=substr($0,p1+1)}
  m==4&&/^A_Dcc./{p1=index($0,":")	# Parse configshow output for DCC_POLICYs
   dcca[cfid,substr($0,7,p1-7)]=substr($0,p1+1)}
  m==4&&/^portNpivLimit:/{															# Parse configshow output for portNpivLimit
   split(substr($0,15),atmp,";")
   for(j in atmp){split(atmp[j],atmp2,",")
    if(d[portindex[atmp2[1]],"fid"]==cfid){											# only set values if port is in current fid
     d[portindex[atmp2[1]],"portnpivlimit"]=atmp2[2]+0}}}
  m==4&&/^portEportCredits./{															# Parse configshow output for portEportCredits, for example portEportCredits.4:25
   split(substr($0,18),atmp,":")
   d[portindex[atmp[1]],"portEportCredits"]=atmp[2]+0}
  m==4&&/^np.meta.simport:/{														# SIM ports
   split($0,atmp,":");split(atmp[2],atmp2,",")										# Separate out comma separated list of SIM port indexes
   for(j in atmp2){d[portindex[atmp2[j]],"sim"]=1}}
  m==4&&/^zone\./&&/,/{																# Any zones with d,i
   tmp1="[;:]"d[cfid,"switchdomain"]","
   if($0~tmp1){tmp=index($0,":")													# Capture zones with d,i for this domain
   zone[cfid,substr($0,6,tmp-6)]=substr($0,tmp+1)}}
  m==4&&/^fcRoute/{gsub(/\./," ")gsub(/:/," ")}										# Capture FCR port config - replace separators
  m==4&&/^fcRoute/&&/xportAdmin ENABLED/{d[portindex[$3],"fcrxportAdmin"]="ENABLED"}
  m==4&&/^fcRoute/&&/fabricId/&&((portindex[$3],"fcrxportAdmin") in d){d[portindex[$3],"fcrfabricid"]=$5}
  m==4&&/^fcRoute/&&/ratov/&&((portindex[$3],"fcrxportAdmin") in d){d[portindex[$3],"ratov"]=$5}
  m==4&&/^fcRoute/&&/edtov/&&((portindex[$3],"fcrxportAdmin") in d){d[portindex[$3],"edtov"]=$5}
  m==4&&/^fcRoute/&&/frontConfigDid/&&((portindex[$3],"fcrxportAdmin") in d){d[portindex[$3],"frontdomain"]=$5}
  m==4&&/^fcRoute/&&/autoElp/&&((portindex[$3],"fcrxportAdmin") in d){d[portindex[$3],"elp"]=$5}
  m==4&&/^portFportBuffers/{   split(substr($0,18),atmp,":")
   d[portindex[atmp[1]],"portFportBuffers"]=atmp[2]+0}
  
  /^## "linkcost/{m=5;next}															# Parse linkcost command output
  m==5&&/^[0-9]/&&/STATIC/{gsub(/\([A-Z_-]+\)/,"");d[$1,"linkcost"]=$2}				# Only save STATIC (user-set) linkcosts
 
  /^## "snmptraps --show port" /{m=6;tmp=0;next}									# Parse snmptraps command output
  m==6{gsub(/ /,"");n=split($0,atmp,"|")}
  m==6&&/^ *[0-9]/{for(i=2;i<n;i++)if(atmp[i])d[i-1"/"atmp[1],"snmptraps"]="Y"}							# For directors
  m==6&&/^Blocked/{atmp[1]=substr(atmp[1],8);for(i=1;i<n;i++){if(atmp[i])d[tmp,"snmptraps"]="Y";tmp++}}	# For pizzaboxes
  
  /^## "slotshow -m" /{m=7;next}													# Parse slotshow command output
  m==7&&$1~/[0-9]/{model[$1]=$5}
  
  /^## "fapwwn/{m=8;next}															# Parse fapwwn command output
  m==8&&/[0-9]/&&NF>2{d[$2"/"$3,"fapwwn"]=$5}										# Only save user-set 
  
  /^## "portcfgtdz/{m=9;next}															# Parse portcfgtdz command output
  m==9&&/ON/{d[$1"/"$2,"portcfgtdz"]=$2}										# Only save tdz ON
  
  /^## "portshow fciptunnel/{m=10;next}												# Begin Parse FCIP tunnel output
  m==10&&/^ Tunnel: VE-Port:/{ p=split($2,a,":"); n=a[2];
	if (d[n,"fid"]==fid){ d[n,"tunnel"]=$2; d[n,"tunnelopts"]="";
	  if(NF>4){
	    d[n,"tunnelopts"]=d[n,"tunnelopts"]" --description \\\""$5;
	    for(i=6;i<=NF;i++){ d[n,"tunnelopts"]=d[n,"tunnelopts"]" "$i };
	    d[n,"tunnelopts"]=d[n,"tunnelopts"]"\\\""
	  }
	}
  }
  m==10&&/^  IP-Extension/{if(d[n,"fid"]==fid){if($3!="Disabled"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ipext enable"}}}
  m==10&&/^  Fastwrite/{if(d[n,"fid"]==fid){if($3!="Disabled"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --fastwrite"}}}
  m==10&&/^  Tape Pipelining/{if(d[n,"fid"]==fid){if($4!="Disabled"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --tape-pipelining"}}}
  m==10&&/^  Compression/{if(d[n,"fid"]==fid){if($3!="None"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --compression "substr($3,0,4)}}}
  m==10&&/^  FC-Compression/{if(d[n,"fid"]==fid){if($4=="(Override)"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --fc-compression "$3}}}
  m==10&&/^  FC-Compression/{if(d[n,"fid"]==fid){if($5=="(Override)"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --fc-compression "substr($3,0,4)"-"$4}}}
  m==10&&/^  IP-Compression/{if(d[n,"fid"]==fid){if($4=="(Override)"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ip-compression "$3}}}
  m==10&&/^  IP-Compression/{if(d[n,"fid"]==fid){if($5=="(Override)"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ip-compression "substr($3,0,4)"-"$4}}}
  m==10&&/^  QoS Distribution/{if(d[n,"fid"]==fid){if($4!="Protocol"||$5!="(FC:50%"||$7!="IP:50%)"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --distribution "tolower($4);for(i=5;i<=NF;i++){if($i!="/"){split($i,ratio,"[:%]");d[n,"tunnelopts"]=d[n,"tunnelopts"]","ratio[2]}}}}}
  m==10&&/^  FC QoS BW Ratio/{if(d[n,"fid"]==fid){if($6!="50%"||$8!="30%"||$10!="20%"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --fc-qos-ratio ";for(i=6;i<=NF;i++){if($i!="/"){split($i,ratio,"%");out=ratio[1]}else{out=","}d[n,"tunnelopts"]=d[n,"tunnelopts"]out}}}}
  m==10&&/^  IP QoS BW Ratio/{if(d[n,"fid"]==fid){if($6!="50%"||$8!="30%"||$10!="20%"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ip-qos-ratio ";for(i=6;i<=NF;i++){if($i!="/"){split($i,ratio,"%");out=ratio[1]}else{out=","}d[n,"tunnelopts"]=d[n,"tunnelopts"]out}}}}
  m==10&&/^  High QoS BW Ratio/{if(d[n,"fid"]==fid){if($6!="50%"||$8!="50%"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --high-qos-ratio ";for(i=6;i<=NF;i++){if($i!="/"){split($i,ratio,"%");out=ratio[1]}else{out=","}d[n,"tunnelopts"]=d[n,"tunnelopts"]out}}}}
  m==10&&/^  Medium QoS BW Ratio/{if(d[n,"fid"]==fid){if($6!="50%"||$8!="50%"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --medium-qos-ratio ";for(i=6;i<=NF;i++){if($i!="/"){split($i,ratio,"%");out=ratio[1]}else{out=","}d[n,"tunnelopts"]=d[n,"tunnelopts"]out}}}}
  m==10&&/^  Low QoS BW Ratio/{if(d[n,"fid"]==fid){if($6!="50%"||$8!="50%"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --low-qos-ratio ";for(i=6;i<=NF;i++){if($i!="/"){split($i,ratio,"%");out=ratio[1]}else{out=","}d[n,"tunnelopts"]=d[n,"tunnelopts"]out}}}}
  m==10&&/^  QoS BW Ratio/{if(d[n,"fid"]==fid){if($5!="50%"||$7!="30%"||$9!="20%"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --qos-bw-ratio ";for(i=5;i<=NF;i++){if($i!="/"){split($i,ratio,"%");out=ratio[1]}else{out=","}d[n,"tunnelopts"]=d[n,"tunnelopts"]out}}}}
  m==10&&/^  IPSec-Policy/{if(d[n,"fid"]==fid){
	  d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ipsec \\\""$3;
	  for(i=4;i<=NF;i++){d[n,"tunnelopts"]=d[n,"tunnelopts"]" "$i}
	  d[n,"tunnelopts"]=d[n,"tunnelopts"]"\\\""
  }}
  m==10&&/^  Load-Level/{if(d[n,"fid"]==fid){if($4!="(Failover"){split($4,a,"(");d[n,"tunnelopts"]=d[n,"tunnelopts"]" --load-level "tolower(a[2])}}}
  m==10&&/^  RemWWN/{if(d[n,"fid"]==fid){if($4!="00:00:00:00:00:00:00:00"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --remote-wwn "$4}}}
  m==10&&/^  FICON                /{if(d[n,"fid"]==fid){if($3!="Disabled"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ficon"}}}
  m==10&&/^    XRC/{if(d[n,"fid"]==fid){if($3!="Disabled"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ficon-xrc"}}}
  m==10&&/^    Tape Pipelining/{if(d[n,"fid"]==fid){if($4=="Read/Write"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ficon-tape-write --ficon-tape-read"}else if($4=="Read-Only"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ficon-tape-read"}else if($4=="Write-Only"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ficon-tape-write"}}}
  m==10&&/^    Read Block id/{if(d[n,"fid"]==fid){if($5!="Disabled"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ficon-read-blk"}}}
  m==10&&/^    Tin Tir/{if(d[n,"fid"]==fid){if($4!="Disabled"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ficon-tin-tir"}}}
  m==10&&/^    DevAck/{if(d[n,"fid"]==fid){if($3!="Disabled"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ficon-dvcack"}}}
  m==10&&/^    Tera Read/{if(d[n,"fid"]==fid){if($4!="Disabled"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ficon-tera-read"}}}
  m==10&&/^    Tera Write/{if(d[n,"fid"]==fid){if($4!="Disabled"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ficon-tera-write"}}}
  m==10&&/^    Print/{if(d[n,"fid"]==fid){if($3!="Disabled"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ficon-print"}}}
  m==10&&/^  FICON Max Read Pipe/{if(d[n,"fid"]==fid){if($6!="32"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --max-read-pipe "$6}}}
  m==10&&/^  FICON Max Write Pipe/{if(d[n,"fid"]==fid){if($6!="32"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --max-write-pipe "$6}}}
  m==10&&/^  FICON Max Read Devs/{if(d[n,"fid"]==fid){if($6!="16"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --max-read-devs "$6}}}
  m==10&&/^  FICON Max Write Devs/{if(d[n,"fid"]==fid){if($6!="16"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --max-write-devs "$6}}}
  m==10&&/^  FICON Write Timer/{if(d[n,"fid"]==fid){if($5!="300"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --write-timer "$5}}}
  m==10&&/^  FICON Write Chain/{if(d[n,"fid"]==fid){if($5!="3200000"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --write-chain "$5}}}
  m==10&&/^  FICON OXID Base/{if(d[n,"fid"]==fid){if($5!="0x9000"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --oxid-base "$5}}}
  m==10&&/^  FICON Debug Flags/{if(d[n,"fid"]==fid){if($5!="0x77c90000"){d[n,"tunnelopts"]=d[n,"tunnelopts"]" --ficon-debug "$5}}}

  /^## "portshow fcipcircuit/{m=11;next}
  m==11&&/^ Circuit/{cid=$2;split($2,a,".");n=a[1];c=a[2];if (d[n,"fid"]==fid){circuits[cid]=cid;circuitopts[n,c]="";}}
  m==11&&/^  Admin\/Oper State/{if(d[n,"fid"]==fid){if($4!="Enabled"){circuitopts[n,c]=circuitopts[n,c]" --admin-status "tolower($4)}}}
  m==11&&/^  IP Addr/{if(d[n,"fid"]==fid){locip=$5;remip=$7;if(locip!="0.0.0.0"&&locip!="::"){remip=$8;circuitopts[n,c]=circuitopts[n,c]" --local-ip "tolower(locip)}if(remip!="0.0.0.0"&&remip!="::"){circuitopts[n,c]=circuitopts[n,c]" --remote-ip "remip}}}
  m==11&&/^  HA IP Addr/{if(d[n,"fid"]==fid){locip=$6;remip=$8;if(locip!="0.0.0.0"&&locip!="::"){remip=$9;circuitopts[n,c]=circuitopts[n,c]" --local-ha-ip "tolower(locip)}if(remip!="0.0.0.0"&&remip!="::"){circuitopts[n,c]=circuitopts[n,c]" --remote-ha-ip "remip}}}
  m==11&&/^  Configured Comm Rates/{if(d[n,"fid"]==fid){if($4!="0"){circuitopts[n,c]=circuitopts[n,c]" --min-comm-rate "$4}if($6!="0"){circuitopts[n,c]=circuitopts[n,c]" --max-comm-rate "$6}}}
  m==11&&/^  Keepalive/{if(d[n,"fid"]==fid){if($5!="(6000"){split($5,a,"(");circuitopts[n,c]=circuitopts[n,c]" --keepalive-timeout "tolower(a[2])}}}
  m==11&&/^  Metric/{if(d[n,"fid"]==fid){if($3!="0"){circuitopts[n,c]=circuitopts[n,c]" --metric "$3}}}
  m==11&&/^  Connection Type/{if(d[n,"fid"]==fid){if($4!="Default"){circuitopts[n,c]=circuitopts[n,c]" --connection-type "tolower($4)}}}
  m==11&&/^  ARL-Type/{if(d[n,"fid"]==fid){if($3=="Reset"){circuitopts[n,c]=circuitopts[n,c]" --arl-algorithm reset"}if($3=="Step"){circuitopts[n,c]=circuitopts[n,c]" --arl-algorithm step-down"}if($3=="Timed-Step"){circuitopts[n,c]=circuitopts[n,c]" --arl-algorithm timed-step-down"}}}
  m==11&&/^  SLA/{if(d[n,"fid"]==fid){if($3!="(none)"){circuitopts[n,c]=circuitopts[n,c]" --sla \\\""$3;for(i=4;i<=NF;i++){circuitopts[n,c]=circuitopts[n,c]" "$i}circuitopts[n,c]=circuitopts[n,c]"\\\""}}}
  m==11&&/^  Failover Group/{if(d[n,"fid"]==fid){if($4!="0"){circuitopts[n,c]=circuitopts[n,c]" --failover-group "$4}}}
  m==11&&/^  L2Cos \(FC:h\/m\/l\)/{if(d[n,"fid"]==fid){if($9!="(Ctrl:0)"){split($9,a,"[:)]");circuitopts[n,c]=circuitopts[n,c]" --l2cos-f-class "a[2]}}}
  m==11&&/^  L2Cos \(FC:h\/m\/l\)/{if(d[n,"fid"]==fid){if($4!="0"){circuitopts[n,c]=circuitopts[n,c]" --l2cos-high "$4}}}
  m==11&&/^  L2Cos \(FC:h\/m\/l\)/{if(d[n,"fid"]==fid){if($6!="0"){circuitopts[n,c]=circuitopts[n,c]" --l2cos-med "$6}}}
  m==11&&/^  L2Cos \(FC:h\/m\/l\)/{if(d[n,"fid"]==fid){if($8!="0"){circuitopts[n,c]=circuitopts[n,c]" --l2cos-low "$8}}}
  m==11&&/^  L2Cos \(IP:h\/m\/l\)/{if(d[n,"fid"]==fid){if($4!="0"){circuitopts[n,c]=circuitopts[n,c]" --l2cos-ip-high "$4}}}
  m==11&&/^  L2Cos \(IP:h\/m\/l\)/{if(d[n,"fid"]==fid){if($6!="0"){circuitopts[n,c]=circuitopts[n,c]" --l2cos-ip-med "$6}}}
  m==11&&/^  L2Cos \(IP:h\/m\/l\)/{if(d[n,"fid"]==fid){if($8!="0"){circuitopts[n,c]=circuitopts[n,c]" --l2cos-ip-low "$8}}}
  m==11&&/^  DSCP \(FC:h\/m\/l\)/{if(d[n,"fid"]==fid){if($9!="(Ctrl:0)"){split($9,a,"[:)]");circuitopts[n,c]=circuitopts[n,c]" --dscp-f-class "a[2]}}}
  m==11&&/^  DSCP \(FC:h\/m\/l\)/{if(d[n,"fid"]==fid){if($4!="0"){circuitopts[n,c]=circuitopts[n,c]" --dscp-high "$4}}}
  m==11&&/^  DSCP \(FC:h\/m\/l\)/{if(d[n,"fid"]==fid){if($6!="0"){circuitopts[n,c]=circuitopts[n,c]" --dscp-med "$6}}}
  m==11&&/^  DSCP \(FC:h\/m\/l\)/{if(d[n,"fid"]==fid){if($8!="0"){circuitopts[n,c]=circuitopts[n,c]" --dscp-low "$8}}}
  m==11&&/^  DSCP \(IP:h\/m\/l\)/{if(d[n,"fid"]==fid){if($4!="0"){circuitopts[n,c]=circuitopts[n,c]" --dscp-ip-high "$4}}}
  m==11&&/^  DSCP \(IP:h\/m\/l\)/{if(d[n,"fid"]==fid){if($6!="0"){circuitopts[n,c]=circuitopts[n,c]" --dscp-ip-med "$6}}}
  m==11&&/^  DSCP \(IP:h\/m\/l\)/{if(d[n,"fid"]==fid){if($8!="0"){circuitopts[n,c]=circuitopts[n,c]" --dscp-ip-low "$8}}}

  /^## "portshow tcl/{m=12;next}
  m==12&&/^ TCL:/{n=$0;if($2!="default"){n="\\\""$2;for(i=3;i<=NF;i++){n=n" "$i}n=n"\\\"";tcl[n]=n;tclopts[n]=""}}
  m==12&&/^ Admin Status:/{if($3=="Enabled"){tclopts[n]=tclopts[n]" --admin-status enable"}}
  m==12&&/^ Priority:/{if($2!=0){tclopts[n]=tclopts[n]" --priority "$2}}
  m==12&&/^ Target:/{if($2!="-"){tclopts[n]=tclopts[n]" --target "tolower($2)}}
  m==12&&/^ VLAN:/{if($2!="ANY"){tclopts[n]=tclopts[n]" --vlan " $2}}
  m==12&&/^ L2COS:/{if($2!="ANY"){tclopts[n]=tclopts[n]" --l2cos "$2}}
  m==12&&/^ DSCP:/{if($2!="ANY"){tclopts[n]=tclopts[n]" --dscp "$2}}
  m==12&&/^ Source Address:/{if($3!="ANY"){tclopts[n]=tclopts[n]" --src-addr "$3}}
  m==12&&/^ Destination Address:/{if($3!="ANY"){tclopts[n]=tclopts[n]" --dst-addr "$3}}
  m==12&&/^ L4 Protocol:/{if($3!="ANY"){tclopts[n]=tclopts[n]" --l4proto "$3}}
  m==12&&/^ Protocol Port:/{if($3!="ANY"){c=split($3,a,"[()]");if(c>1){tclopts[n]=tclopts[n]" --proto-app \\\""a[2];for(i=4;i<=NF;i++){split($i,a,")");tclopts[n]=tclopts[n]" "a[1]}tclopts[n]=tclopts[n]"\\\""}else{tclopts[n]=tclopts[n]" --proto-port "$3}}}
  m==12&&/^ Action:/{if($2!="Allow"){if(NF==3){tclopts[n]=tclopts[n]" --action "tolower($3)"-"tolower($2)}else{tclopts[n]=tclopts[n]" --action " tolower($2)}}}
  m==12&&/^ RST Propagation:/{if($3!="Disabled"){tclopts[n]=tclopts[n]" --rst-propagation enable"}}
  m==12&&/^ Segment Preservation:/{if($3!="Disabled"){tclopts[n]=tclopts[n]" --segment-preservation enable"}}
  m==12&&/^ Non Terminated:/{if($3!="Disabled"){tclopts[n]=tclopts[n]" --non-terminated enable"}}

  /^## "portaddress/{m=13;next}	# Parse portaddress command output 
  m==13&&$NF=="Y"{d[$2"/"$3,"portaddress"]=$4}	# Only save user-set 

  /^## "lscg/{m=14;next}															# Parse lscg (rewritten lscfg) command output
  m==14&&/^FID/{lscg[$1]=substr($0,index($0,$2))}

  END{nports=split(ports,port," ");													# BEGIN SYNTHESIS All data is in array, so now synthesize commands for each switch
   if(fid){for(fid in fids){doit(fid)}}else{doit("")}								# execute doit on each VF or non-VF switch
   if(fid){for(fid in fids){post_doit(fid)}}else{post_doit("")}						# execute post_doit on each VF or non-VF switch
  }	
   
  func doit(fid, tmp,tmp2,atmp,atmp2,j,c,k,zs){										# doit actually synthesizes the commands, parameters spaced to right are effectively local variables
   exe("switchdisable",fid)															# make sure switch is disabled, so dont have to do individual port disables/enables
   
   tmp=split(lscg["FID_"fid],atmp," ")												# lscfg for core blades only
   for(i=1;i<=tmp;i++){
    if(model[atmp[i]+0]~/^CR/){														# if core blade
	 split(atmp[i],atmp2,"/")
     exe("lscfg --config "fid" -slot "atmp2[1]" -port "atmp2[2],fid,"printf y\\\\n|")}}

   for(j=1;j<=nports;j++){															# do all port-level commands
    if(!fid || d[port[j],"fid"]==fid){												# if non-VF, or if this port is in the current fid

     if((port[j],"fapwwn") in d){													# fapwwn
       exe("fapwwn --assign -port "port[j]" -v "d[port[j],"fapwwn"],fid)}

     if((port[j],"portaddress") in d){	# portaddress 
       exe("portaddress --bind "port[j]" "d[port[j],"portaddress"],fid)}

     if((port[j],"portcfgtdz") in d){												# portcfgtdz
       exe("portcfgtdz --enable "port[j],fid)}

     if(d[port[j],"proto"]=="ETH"){													# portcfgflexport for ETH FCOE ports
      exe("portcfgflexport --proto eth "port[j],fid)	  
      if(d[port[j],"speed"]~/10G|25G/){
       exe("portcfgbreakout --enable "port[j],fid)}}
    
     if((port[j],"portnpivlimit") in d){											# portCfgNPIVPort
      exe("portCfgNPIVPort --setloginlimit "port[j]" "d[port[j],"portnpivlimit"],fid)}
 
     if((port[j],"portEportCredits") in d){											# portcfgeportcredits
      exe("portcfgeportcredits --enable "port[j]" "d[port[j],"portEportCredits"],fid)}
 
     if((port[j],"portFportBuffers") in d){											# portcfgfportbuffers
      exe("portcfgfportbuffers --enable "port[j]" "d[port[j],"portFportBuffers"],fid)}
 
     if((port[j],"fcrxportAdmin") in d){											# FCR Build the portcfgexport command
	  if(d[port[j],"elp"]=="0"){elp="2"}else{elp="1"}
      exe("portcfgexport "port[j]" -a 1 -f "d[port[j],"fcrfabricid"]" -d "d[port[j],"frontdomain"]" -p 0 -t "elp" -r "d[port[j],"ratov"]" -e "d[port[j],"edtov"],fid)}
 
     if(d[port[j],"speed"]~/G$/){													# portcfgspeed
	  if(!(model[port[j]+0]~/CR32-[48]/ && d[port[j],"speed"]=="32G"))				# ignore 32G on Gen6 core blade CR32-4 or CR32-8 since that is default
       exe("portcfgspeed "port[j]" "d[port[j],"speed"]+0,fid)}	
 
     if((port[j],"sim") in d){														# SIM port - must be after portcfgspeed
      if("12" in model){tmp=tr_A(d[port[j],"index"])}else{tmp=tr_V(d[port[j],"index"])}		# if there is a slot 12, then it is an Allegience	   
      exe("flow --control -simport "tmp" -enable",fid)}
    
     if((port[j],"linkcost") in d){													# linkcost			must have a value
	  if((port[j],"fcrxportAdmin") in d)
	   exe("fcrrouterportcost "port[j]" "d[port[j],"linkcost"],fid)					# Use different command for ExPorts
      else{exe("linkcost "port[j]" "d[port[j],"linkcost"],fid)}}

     if(d[port[j],"snmptraps"]=="Y"){												# snmptraps
      exe("snmptraps --block -port "port[j],fid)}	
 
     split(d[port[j],"portcfg"],atmp,",")											# separate bitfields for this port, synthesis below this depends on these bitfields
     tmp2=and(strtonum(atmp[1]),strtonum("0x3000"))									# mask bitfields to determine feature enabled
     if(tmp2){tmp="portcfglongdistance "port[j]" "									# portcfglongdistance
      if(tmp2==strtonum("0x1000")){tmp=tmp "LE "}
      if(tmp2==strtonum("0x2000")){tmp=tmp "LD "}
      if(tmp2==strtonum("0x3000")){tmp=tmp "LS "}
      if(and(strtonum(atmp[1]),strtonum("0x100000"))==strtonum("0x100000")){ tmp=tmp "1"}else{tmp=tmp "0"}
      if((port[j],"portDistance") in d){tmp=tmp" -distance "d[port[j],"portDistance"]}
      if((port[j],"portEstdBuffers") in d){tmp=tmp" -buffers "d[port[j],"portEstdBuffers"]}
      if((port[j],"portFrameSize") in d && d[port[j],"portFrameSize"]>0){tmp=tmp" -framesize "d[port[j],"portFrameSize"]}
      if(and(strtonum(atmp[3]),strtonum("0x40000000"))==strtonum("0x40000000")){tmp=tmp " -fecdisable"}
      exe(tmp,fid)}
      
     #print "port="port[j]"  atmp[3]="atmp[3]
     tmp2=and(strtonum(atmp[3]),strtonum("0x1f00000"))								# portcfgspeed max - must be after portcfgspeed
     tmp="portcfgspeed "port[j]" "d[port[j],"speed"]+0" -m "									
     if(tmp2==strtonum("0x1000000")){tmp=tmp "32";exe(tmp,fid)}
     if(tmp2==strtonum("0x0f00000")){tmp=tmp "16";exe(tmp,fid)}
     if(tmp2==strtonum("0x0e00000")){tmp=tmp "8";exe(tmp,fid)}
     if(tmp2==strtonum("0x0d00000")){tmp=tmp "4";exe(tmp,fid)}
      
 
     if(and(strtonum(atmp[2]),strtonum("0xc0000000"))){								# portcfgqos
	  exe("portcfgqos --enable "port[j],fid)}
     if(and(strtonum(atmp[2]),strtonum("0x2000"))){									# portcfgqos for csctl
	  exe("portcfgqos --enable "port[j]" csctl_mode",fid,"printf y\\\\n|")}
 
     if(and(strtonum(atmp[1]),strtonum("0x2"))){									# portcfg mirrorport
	  exe("portcfg mirrorport "port[j]" --enable",fid,"printf y\\\\n|")}
 
     if(and(strtonum(atmp[1]),strtonum("0x10"))){									# portcfgnpivport
	  exe("portcfgnpivport "port[j]" 0",fid)}
 
     if(and(strtonum(atmp[1]),strtonum("0x10000000"))==0){							# portcfgtrunkport
	  exe("portcfgtrunkport "port[j]" 0",fid)}

     if(and(strtonum(atmp[1]),strtonum("0x10000000"))){								# portcfgtrunkport   This is the default so should not be needed
      exe("portcfgtrunkport "port[j]" 1",fid)}
 
     if(and(strtonum(atmp[1]),strtonum("0x10000"))){								# portcfgislmode
	  exe("portcfgislmode "port[j]" 1",fid)}
 
     if(and(strtonum(atmp[1]),strtonum("0x800000"))){								# portcfgeport
	  exe("portcfgeport "port[j]" -p 0",fid)}
     if(and(strtonum(atmp[2]),strtonum("0x4000"))){									# portcfgeport also, option 2 is in second bitfield
	  exe("portcfgeport "port[j]" -p 2",fid)}

     if(and(strtonum(atmp[2]),strtonum("0x200000"))){								# portcfglosstov -enable_fixed (Mode 1): losig Word 1 Bit 21
	  exe("portcfglosstov "port[j]" 1",fid)}

     if(and(strtonum(atmp[3]),strtonum("0x8000"))){									# portcfglosstov --enable_all (Mode 2): losig1 Word 2 Bit 15
	  exe("portcfglosstov "port[j]" 2",fid)}

     if(and(strtonum(atmp[2]),strtonum("0x200"))){									# portcfgcompress: compression Word 1 Bit 9
	  exe("portcfgcompress --enable "port[j],fid)}

     if(and(strtonum(atmp[2]),strtonum("0x80000"))){								# portcfgcreditrecovery: cr_recov Word 1 Bit 19
	  exe("portcfgcreditrecovery --disable "port[j],fid)}

     if(and(strtonum(atmp[2]),strtonum("0x1"))){									# portcfgfaultdelay: fault_delay Word 1 Bit 0
	  exe("portcfgfaultdelay "port[j]" 1",fid)}

     if(and(strtonum(atmp[3]),strtonum("0x2000000"))){								# portcfgflogilogout: npiv_base_logo Word 2 Bit 25
	  exe("portcfgflogilogout --enable "port[j],fid)}

     if(and(strtonum(atmp[1]),strtonum("0x8000"))){									# portcfgpersistentdisable
      tmp="portcfgpersistentdisable "port[j]
      if(d[port[j],"portCfgDisableReason"]){										# if there is a reason
        tmp=tmp" -r \\\""d[port[j],"portCfgDisableReason"]"\\\""}
      exe(tmp,fid)}

     if((port[j],"tunnel") in d){
      exe("portcfg fciptunnel "port[j]" create"d[port[j],"tunnelopts"],fid)}		# fciptunnel

     for (cid in circuits) {														# fcipcircuit
      split(cid, a, ".");n=a[1];c=a[2];
      if (n == port[j]){
       exe("portcfg fcipcircuit "n" create "c" "circuitopts[n,c],fid)
      }
     }
    }																				# end of FID
   }																				# End of specific port-related processing
   
   for(j in ptab){																	# porttrunkarea
    if(!fid || d[ptab[j],"fid"]==fid){												# if non-VF, or if this port is in the current fid
     if("12" in model){tmp=tr_A(j)}else{tmp=tr_V(j)}								# if there is a slot 12, then it is an Allegience
     exe("porttrunkarea --enable "ptab[j]"-"ptae[j]" -index "tmp,fid)}}

   tmp=0;for(j in dccd){split(j,atmp,SUBSEP)										# Check for any DCC Policies
    if(!fid || atmp[1]==fid){tmp++}}												# if non-VF, or if this index is in the current fid
   zs=0;for(j in zone){split(j,atmp,SUBSEP)											# Check if any zones to modify
     if(!fid || atmp[1]==fid){zs++}}												# if non-VF, or if this index is in the current fid
   exe("switchcfgpersistentenable;switchenable",fid)								# If there is no other config in this FID, then no delay
   if(tmp||zs){print "# Wait for fabric to come up since DCC policies must be defined or zones modified when fabric is up"}
   for(j in zone){split(j,atmp,SUBSEP)												# separate into fid and zone name
    if(!fid || atmp[1]==fid){tmp=split(zone[j],atmp1,";")							# if non-VF, or if this index is in the current fid	 
     for(k=1;k<=tmp;k++){															# for each member in the zone
      if(2==split(atmp1[k],atmp2,",")){												# if D,I is found
	   if(atmp2[1]==d[fid,"switchdomain"]){											# Only translate if D,I is the local switch domain
	    print "# Zone changes are not officially supported, so the following commands are commented out.  Take a look and see if they are applicable to you."
        if("12" in model){tmp3=tr_A(atmp2[2])}else{tmp3=tr_V(atmp2[2])}				# Translate port index to new Gen7 index in either Allegience or Venator
        exe("zoneremove \\\""atmp[2]"\\\", \\\""atmp1[k]"\\\";zoneadd \\\""atmp[2]"\\\", \\\""atmp2[1]","tmp3"\\\";printf \\\"y\\ny\\n\\\"|cfgsave",fid,"# ")}}}}}			# replace D,I member from zone
   
   c=0;for(j in dcca){c+=dcc_lookup(j,dcca)}										# secpolicycreate for Active DCC_POLICYs 
   if(c){exe("secpolicyactivate",fid,"printf y\\\n|")}								# if any - activate all that were defined
   c=0;for(j in dccd){if(!(j in dcca)){c+=dcc_lookup(j,dccd)}}						# Dont define if already active
   #not needed since Must do this after every command since is session based  if(c){exe("secpolicysave",fid)}	# if any - save all that got defined without being activated
  }																					# End of func doit()

  func post_doit(fid, tmp,tmp2,atmp,atmp2,j,c,k,zs){								# post_doit actually synthesizes the commands to be executed after the main doit() commands
   if (!fid || (fid==deffid)) {
    for (n in tcl){exe("portcfg tcl "n" create "tclopts[n],fid)}
   }
  }																					# End of func post_doit()
  
  func dcc_lookup(j,dcc, atmp,atmp2,atmp3,atmp4,tmp,tmp1,tmp3,k,i,line,n){			# secpolicycreate with index lookup, parameters spaced to right are effectively local variables 
   split(j,atmp,SUBSEP)																# separate into fid and DCC_POLICY name 
   if(!fid || atmp[1]==fid){														# if non-VF, or if this index is in the current fid 
    tmp1=split(dcc[j],atmp4,";")													# separate data into WWN lists 
    for(i=1;i<=tmp1;i++){ 															# for each wwn/index 
     n=split(atmp4[i],atmp2,"[()]")													# separate data into WWN and comma delimited port index list 
     if(n>1){																		# if there are indexes 
      if(d[fid,"switchwwn"]==atmp2[1]){												# Only translate indexes if this is the local WWN and there are indexes 
       tmp=split(atmp2[2],atmp3,",")												# separate list of port indexes 
       tmp3="";for(k=1;k<=tmp;k++){													# for each port index 
        if("12" in model){tmp3=tmp3","tr_A(atmp3[k])}else{tmp3=tmp3","tr_V(atmp3[k])}}	# Translate port index to new Gen7 index in either Allegience or Venator 
       line=line atmp2[1]"["substr(tmp3,2)"];"										# add substituted indexes to line 
      }else{line=line atmp2[1]"["atmp2[2]"];"}										# if not local WWN, just copy the indexes to line 
     }else{line=line atmp2[1]";"}}													# if no indexes, just copy WWN to line 
    argct=split(line,argval,";") 													#Separate the secpolicycreate args
    exe("secpolicycreate \\\""atmp[2]"\\\",\\\""argval[1]"\\\";secpolicysave",fid) 						#Add remaining args using secpolicyadd
    for(i=2;i<argct;i++){ 															# for each wwn/index
     exe("secpolicyadd \\\""atmp[2]"\\\",\\\""argval[i]"\\\";secpolicysave",fid)}
    return 1}}

  func exe(cmd,fid,prefix){															# use fosexec if VF, or just the command if non-VF
   if(fid){print prefix"fosexec --fid "fid" -cmd \""cmd"\""}else{print prefix cmd}}
   
  func tr_V(x){return x+32*int(x/64)+16*int(x/272)-720*int(x/736)-48*int(x/784)}	# Translate Gen6 index to Gen7 index on Venator or Allegience
  func tr_A(x){return x+80*int(x/16)-752*int(x/128)+720*int(x/384)-80*int(x/400)-48*int(x/416)-80*int(x/432)-1280*int(x/768)\
 +80*int(x/800)+48*int(x/832)+80*int(x/864)-16*int(x/1152)-80*int(x/1168)-48*int(x/1184)}' < $1 | tee $outputFile
 chmod +x $outputFile; }
 
 # lscfg with much more useful, sorted output.  Works on Pizzaboxes and Directors.  Includes GE ports - by Brian Rose
lscg(){ { lscfg --show;lscfg --show -ge; }|awk -F\| 's{gsub(/ /,"")}
 /^ *[0-9]/{if(m<NF)m=NF;n++;for(i=2;i<=NF;i++)if($i){j[$i]=j[$i]" "i-1"/"z $1}}
 /^FID/{$0=substr($0,4);for(i=1;i<=NF;i++)if($i){j[$i]=j[$i]" "z n++;}}
 /^GEPort/{if(!g)n=0;g++;z="ge"}/^Slot|^Port/{s++}!s
 END{for(q in j){if(m){w="FID_"q"\t";x=split(j[q],y," ");
  for(i=1;i<=m-1;i++)for(k=1;k<=x;k++)if(y[k]+0==i)w=w y[k]" ";print w
  }else print "FID_"q,j[q]}}'; }
  
# Combines list of individual ports into ranges of ports - by Brian Rose
cmbg(){ awk '/^FID/{v=$1"\t";g=0
 for(i=2;i<=NF;i++){n=split($i,t,"/")
  if(g&&(t[n]-z[n]==1||s(t[n])-s(z[n])==1)&&t[n-1]==z[n-1])r=t[n];
  else{f();v=v" "$i}g=split($i,z,"/")}f();$0=v}1
func s(x){sub(/ge/,"",x);return x}func f(){if(r)v=v"-"r;r=0}'; }

main "$@"											# using a "main" function allows program to be shown first, and then subroutines 
