Re: Code for :"Re: HERE document failed && Re: /dev/fd/62: No such file or directory"

2014-07-31 Thread Linda Walsh



Chet Ramey wrote:

but it seemed to work and not be at fault upon further
exploration.  Now it's one of 2 Associative arrays (often
called "'map's" in the code where they are used as such)
that is failing due to illegal subscript messages. 


The fact that one of the maps works and the other does not
seems odd.  They are both initialized the same way.


Have you considered printing the value you're trying to use as a
subscript before the failing line is executed?



It's been a while, but I seem to remember doing that
and setting -x at the beginning of the script and picking through
that post-boot.

I try it again... might easily get a different result
with how things are going for me lately...




Re: Code for :"Re: HERE document failed && Re: /dev/fd/62: No such file or directory"

2014-07-31 Thread Chet Ramey
> but it seemed to work and not be at fault upon further
> exploration.  Now it's one of 2 Associative arrays (often
> called "'map's" in the code where they are used as such)
> that is failing due to illegal subscript messages. 
> 
> The fact that one of the maps works and the other does not
> seems odd.  They are both initialized the same way.

Have you considered printing the value you're trying to use as a
subscript before the failing line is executed?

> Is it really the case that now that the problem is better
> defined, that it really is just some problem in bash
> that can only reproduced on a booting system?

Unlikely.

-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/



Re: Code for :"Re: HERE document failed && Re: /dev/fd/62: No such file or directory"

2014-07-30 Thread Linda Walsh

I got various suggestions for getting my script to work at boot time,

and any of them might have been applicable before I'd gotten to the current
problem...

In particular the <<<"$VAR" construct where VAR was holding
output from a program.. was something on my "iffy" list,
but it seemed to work and not be at fault upon further
exploration.  Now it's one of 2 Associative arrays (often
called "'map's" in the code where they are used as such)
that is failing due to illegal subscript messages. 


The fact that one of the maps works and the other does not
seems odd.  They are both initialized the same way.

I've also tried resetting the environment...
(env -i bash --norc --noprofile;
bash-4.2$ ...command works...)

Is it really the case that now that the problem is better
defined, that it really is just some problem in bash
that can only reproduced on a booting system?

Note -- if you invoke the script with with no parms, it
display normal options "ifmap" (shows current mapping)
and "remap" which does a verify on the names and does
renaming if needed (based on it's internal table -- i.e.
don't use this unless you've adapted it to your system).

undocumented: if you invoke it with 'start' it does the "remap" function.

Other than a few left-over functions from earlier debug
attempts (tests removed, but some of the functions remain
so I can maybe move them to a library later  (e.g. - isarray
& varflags), it is fairly lean for design of non-throwaway code.










Re: Code for :"Re: HERE document failed && Re: /dev/fd/62: No such file or directory"

2014-07-29 Thread Angel
Greg Wooledge wrote:
> The 'read' example will not work as you've written it.  The change to
> the shell variable 'out' will be lost when the pipeline terminates.
> (But you can get a very recent bash release and set the "lastpipe"
> shopt to work around this.)
> 
> If the while loop also tries to set shell variables, then it will have
> the same problem (and the same possible workaround).

You are right. Turns out I didn't reset the variable between tests.


Or you can put the inside-code into brackets :)




Re: Code for :"Re: HERE document failed && Re: /dev/fd/62: No such file or directory"

2014-07-29 Thread Linda Walsh

Greg Wooledge wrote:

read out < <(declare -p "$var")


That code actually isn't called.  It's used by "isarray" to tell me whether
or not a var is an array.

The code that doesn't work is the line with the comment "line 233".
(which is now line 235 from the latest error message.

 service boot.clock start
assign_netif_names=/etc/init.d/boot.assign_netif_names start
ifname=eth0, hwaddr=00:15:17:bf:be:b2
ifname=eth1, hwaddr=00:15:17:bf:be:b3
ifname=eth2, hwaddr=00:26:b9:48:71:e2
ifname=eth3, hwaddr=00:26:b9:48:71:e4k
ifname=eth4, hwaddr=a0:36:9f:15:c9:c0
ifname=eth5, hwaddr=a0:36:9f:15:c9:c2
/etc/init.d/boot.assign_netif_names: line 235: act_hw2if: bad array 
subscript
/etc/init.d/boot.assign_netif_names: line 235: act_hw2if: bad array 
subscript
/etc/init.d/boot.assign_netif_names: line 235: act_hw2if: bad array 
subscript
/etc/init.d/boot.assign_netif_names: line 235: act_hw2if: bad array 
subscript
/etc/init.d/boot.assign_netif_names: line 235: act_hw2if: bad array 
subscript
/etc/init.d/boot.assign_netif_names: line 235: act_hw2if: bad array 
subscript


Note that according to the "printf in "read_actuals", the values are 
correctly

being read in from my "here var".

Note, you can't use an assignment there.

It's reading names+hwaddrs of the net devs @ boot
in "get_net_IFnames_hwaddrs".  That requires line and field
splitting.


Now that I'm writing about it -- I'm thinking that
it doesn't like me using the hwaddr's  @ boot time as hash subscripts.

That's what I don't understand.  It works "normally", but
why would "hashes" fail at boot?  I couldn't think of how they'd
be implemented to use some non-existent service, so I don't
know which resource lack is causing the fail.


I won't even try to guess why she can't just do out=$var ... there is
probably some extremely silly reason that will just make me want to slam
my head into my desk
  

---
Yeah, like multiple lines and fields in "$var"...




Re: Code for :"Re: HERE document failed && Re: /dev/fd/62: No such file or directory"

2014-07-29 Thread Greg Wooledge
On Tue, Jul 29, 2014 at 10:21:36PM +0200, Angel wrote:
> What surprises me is that the only use of here-docs (actually
> here-strings) in your script are process substitutions:
> > read out <<<$(declare -p "$var" )
> > while ... done <<<"$(get_net_IFnames_hwaddrs)"
> 
> When it looks simpler to write the non-here version:
> > declare -p "$var" | read out
> > get_net_IFnames_hwaddrs | while ...

The 'read' example will not work as you've written it.  The change to
the shell variable 'out' will be lost when the pipeline terminates.
(But you can get a very recent bash release and set the "lastpipe"
shopt to work around this.)

If the while loop also tries to set shell variables, then it will have
the same problem (and the same possible workaround).

It looks like Linda's original script was doing something like this:

read out < <(declare -p "$var")

and she discovered that she couldn't use process substitutions in this
boot script (presumably because Linux's /dev/fd/ file system wasn't
mounted yet), so she tried to replace it with a here-document, and now has
learned that /tmp is not mounted (or is mounted read-only) at that point.

I won't even try to guess why she can't just do out=$var ... there is
probably some extremely silly reason that will just make me want to slam
my head into my desk



Re: Code for :"Re: HERE document failed && Re: /dev/fd/62: No such file or directory"

2014-07-29 Thread Angel
Linda Walsh wrote
> 
> Andreas Schwab wrote:
> > Linda Walsh  writes:
> > 
> >>Except that in-line HERE docs don't need to be implemented
> >> through a tmp file unless you want to slow things down.
> >>They should be read out of memory and NOT transfered to
> >> to non-existent, external storage.
> > 
> > You need a file descriptor for your memory storage.
> ---
> Why?

Because that's what the input command expects: your HERE-string *when it
reads its standard input* (fd 0)

You could implement it with pipes, but as you would need a thread to
write the partially-read string, just using a file is simpler. And as
you can write it into a deleted file, the effect on storage should be
minimal.

You should however be able to translate “foo << read out <<<$(declare -p "$var" )
> while ... done <<<"$(get_net_IFnames_hwaddrs)"

When it looks simpler to write the non-here version:
> declare -p "$var" | read out
> get_net_IFnames_hwaddrs | while ...


Regards




Re: Code for :"Re: HERE document failed && Re: /dev/fd/62: No such file or directory"

2014-07-29 Thread Greg Wooledge
On Tue, Jul 29, 2014 at 12:06:41PM -0700, Linda Walsh wrote:
> Andreas Schwab wrote:
> >You need a file descriptor for your memory storage.
> ---
> Why?

A here-document is a redirection.  All it does it change where stdin
comes from.  There has to be a place for file descriptor 0 to point to.
This can be a real file on disk, or one end of a pipe().

I'm not aware of any shells that use a multi-process pipe() implementation
for here-documents.  Maybe this is just historical inertia, or maybe it's
because a temporary file can be lseek()ed, which gives the most flexibility
for the processes that are reading them.  Or maybe it's because a temp
file is considered less of a resource waste than an extra process.

I really do advise you to simplify your boot scripts.  Boot scripts run in
minimalist environments, where advanced features are not always available.
Boot scripts also typically are not run by bash; they're run by /bin/sh
(or even /sbin/sh), which is more likely to be some stripped-down POSIX
shell than it is to be bash.

If you've got some big static block of text that you need to feed to a
daemon at boot time, maybe it would be appropriate to stick this text in
a config file (/etc/default/yourdaemon or /etc/yourdaemon/startup.text or
something like that).  Then you can redirect from that file instead of
using a here-document buried in a boot script.  From a system administration
perspective, this separation of code from data would be a lot cleaner.



Re: Code for :"Re: HERE document failed && Re: /dev/fd/62: No such file or directory"

2014-07-29 Thread Linda Walsh



Andreas Schwab wrote:

Linda Walsh  writes:


Except that in-line HERE docs don't need to be implemented
through a tmp file unless you want to slow things down.
They should be read out of memory and NOT transfered to
to non-existent, external storage.


You need a file descriptor for your memory storage.

---
Why?

If it is the case that you can't rely on OS services, you are
saying you can't access memory or create a virtual descriptor
that reads out of a large malloc'ed buffer?

Both C++ and Perl have routines to do I/O on strings directly
that don't go through system file descriptors to do it.

Last I checked, 'C' was a common denominator for both as well
as Bash.  So why should it be the case that Bash can't do it when
it is the primary system shell available at boot.

I wrote my own line-splitting, word splitting and buffering code
to avoid libc buffering to talk to files in "proc", repeatedly
w/o closing & reopening.  It's mostly in C and was relatively
simple compared to the work of writing a simple scheduler.

There's no reason for me to expect that a system shell wouldn't
have such available.




Re: Code for :"Re: HERE document failed && Re: /dev/fd/62: No such file or directory"

2014-07-29 Thread Andreas Schwab
Linda Walsh  writes:

>   Except that in-line HERE docs don't need to be implemented
> through a tmp file unless you want to slow things down.
>   They should be read out of memory and NOT transfered to
> to non-existent, external storage.

You need a file descriptor for your memory storage.

Andreas.

-- 
Andreas Schwab, SUSE Labs, sch...@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."



Re: Code for :"Re: HERE document failed && Re: /dev/fd/62: No such file or directory"

2014-07-28 Thread Linda Walsh



Greg Wooledge wrote:

On Fri, Jul 25, 2014 at 04:44:27PM -0700, Linda Walsh wrote:

FWIW, this script DOES work interactively in normal operation.

Just when the system is in pre-single-user state and not
much in the way of resources is available that it blows.


Then you are attempting to use operating system features that haven't
been initialized yet.  Stop doing that.


Except that in-line HERE docs don't need to be implemented
through a tmp file unless you want to slow things down.
They should be read out of memory and NOT transfered to
to non-existent, external storage.

Maybe POSIX says differently, but I doubt it differentiates
when you are allowed to use features based on when you run the shell.




Here documents create temporary files, possibly in /tmp, or possibly in
whatever directory $TMPDIR points to.  So, /tmp (or /var/tmp or whatever)
must be mounted and writable.


Is that part of a standard somewhere?   The point is to similate
an input stream.  Wouldn't it be more portable to do that from memory?




Process substitutions **ON LINUX** use /dev/fd/* entries, which are
in a special file system that must be mounted.  Process substitutions
on other operating systems may use that, or named pipes, or even
temporary files.


I'll allow those as they are too new to really be relying on,
but HERE docs are basic, and shouldn't need external run-time support for
the type of stuff I'm doing.



In any case, the problem is clearly that your script is trying to use
features that aren't available yet, at that point in the boot process.

---
Like reading another process's output so I can alter
variables that are in the main thread.

The other methods for reading in data reverse the reader/writer
and put the reader into a child such that it can't modify variables
in the running script.



Rewrite the script to avoid using those features, or run it at a
different point in the boot process.


I have rewritten it to avoid the process substitutions and fell
back to HERE docs for that.  There is no standard or documentation about
what parts of a POSIX shell are not available at boot time or how to
work around the deficiencies.

Also it isn't easy to run things elsewhere in the boot script, as I'll
likely have to run systemd at soem point and it will just take over and
I'll have no control of when things run, so I'm doing some early initialization
so I can then turn over the control thread to something else.

For example, I also have to mount "/usr" and "/usr/share" before
I can "boot", or systemd won't be happy.




Too large.  Trim it down to the smallest possible case that still
exhibits the problem.  But even then, I'm sure you already know what
the problem is.


That's not easy, since by definition, it only works when there
is no environment to support trimming it.


(P.S. I despise that "let me figure out the order for you" crap that
Debian has started doing.  What a disaster.  How in the hell is a
sysadmin supposed to add a boot script now, and make sure it runs at
the right point)


You aren't supposed to be adding boot scripts...

Wait till they get the walled garden up around PC's w/secure boot
and only allowing signed apps.

G.



Re: Code for :"Re: HERE document failed && Re: /dev/fd/62: No such file or directory"

2014-07-28 Thread Greg Wooledge
On Fri, Jul 25, 2014 at 04:44:27PM -0700, Linda Walsh wrote:
> FWIW, this script DOES work interactively in normal operation.
> 
> Just when the system is in pre-single-user state and not
> much in the way of resources is available that it blows.

Then you are attempting to use operating system features that haven't
been initialized yet.  Stop doing that.

Here documents create temporary files, possibly in /tmp, or possibly in
whatever directory $TMPDIR points to.  So, /tmp (or /var/tmp or whatever)
must be mounted and writable.

Process substitutions **ON LINUX** use /dev/fd/* entries, which are
in a special file system that must be mounted.  Process substitutions
on other operating systems may use that, or named pipes, or even
temporary files.

In any case, the problem is clearly that your script is trying to use
features that aren't available yet, at that point in the boot process.
Rewrite the script to avoid using those features, or run it at a
different point in the boot process.

> #!/bin/bash
> 
> ### BEGIN INIT INFO
> # Provides:   net-devices

Too large.  Trim it down to the smallest possible case that still
exhibits the problem.  But even then, I'm sure you already know what
the problem is.

(P.S. I despise that "let me figure out the order for you" crap that
Debian has started doing.  What a disaster.  How in the hell is a
sysadmin supposed to add a boot script now, and make sure it runs at
the right point)



Code for :"Re: HERE document failed && Re: /dev/fd/62: No such file or directory"

2014-07-25 Thread Linda Walsh



Chet Ramey wrote:

Maybe you should post your script so readers can take a look.  It's
unlikely that there is a bug in here-documents, but it's possible.


If you ask for it...   I "inlined" the needed library functions,
so should run standalone.

FWIW, this script DOES work interactively in normal operation.

Just when the system is in pre-single-user state and not
much in the way of resources is available that it blows.

Right now only have 'start' implemented, as there is little call
for deconstructing network configs when the system is going down.

'ifmap' by itself should show current eth-dev mappings.

Note, buried in this code are absolute numbers (MAC addrs),
so to test on another machine they would need to be changed.

Have intended to put "site-local" info in a config file, but
as it doesn't workhaven't spent alot of time on expanding it.



--- ifmap -

#!/bin/bash

### BEGIN INIT INFO
# Provides:   net-devices
# Required-Start: boot.udev boot.device-mapper boot.localfs
# Required-Stop:  $null
# Default-Start:   B
# Default-Stop:
# Short-Description:   order net devices
# Description: order net devs if needed
### END INIT INFO
#
# assign network names as rc-script
#   L A Walsh, (free to use/modify/distribute to nice people) (c) 2013-2014
#
#include standard template:
# gvim=:SetNumberAndWidth
echo "assign_netif_names=$0 $@"
_prgpth=${0:?}; _prgpth=${_prgpth#-} _prg=${_prgpth##*/}; 
_prgdr=${_prgpth%/$_prg}
[[ -z $_prgdr || $_prg == $_prgdr ]] && _prgdr="$PWD"
#if ! typeset -f include >&/dev/null ;then
# source ${_LOCAL_DIR:=/etc/local}/bash_env.sh;
#fi
export PATH="/etc/local/bin:/etc/local/lib:$PATH"
export 
PS4='>>${BASH_SOURCE:+${BASH_SOURCE[0]}}#${LINENO}${FUNCNAME:+(${FUNCNAME[0]})}> '


#include stdalias (needed entries included below)
shopt -s extglob expand_aliases

alias dcl=declare sub=function
alias int=dcl\ -i   map=dcl\ -A   hash=dcl\ -Aarray=dcl\ -a
alias lower=dcl\ -l upper=dcl\ -u string=dcl  my=dcl
alias map2int=dcl\ -AiintArray=dcl\ -ia

#include rc.status  -- essential funcs included below:
int rc_status=0
sub rc_reset { rc_status=0; }
sub rc_status {
  rc_status=$?;
  if ((rc_status))  && { (($#)) && [[ $1 = -v ]] ; }; then
echo "Abnormal rc_status was $rc_status)."
  elif (($#)) && [[ $1 = -v ]] ; then
echo "rc_status: ok"
  fi
}
sub rc_exit {
  rc_status=$?;
  rc_status
  exit $rc_status
}

# need to list commands here:
# modprobe

sub warn () { local msg="Warning: ${1:-"general"}"
  echo "$msg" >&2
}

sub die () { int stat=$?; local msg="Error. ${1:-"unknown"}"
  echo "$msg (errno=$stat)" >&2
  (exit $stat);
  rc_status -v
  rc_exit
  exit $stat
}

if [[ -z $(type -P modprobe) ]]; then
  export PATH=/bin:/sbin:/usr/bin:/usr/sbin:$PATH
fi

if [[ -n $(type -P modprobe) ]]; then
  alias modprobe="$(type -P modprobe)"
else
  #delay failure until use
  alias modprobe="die 'cannot load required modules'"
fi

if [[ -z $(type -P ip ) ]]; then
  die "Cannot find 'ip' util -- needed for network setup"
fi

alias ip="$(type -P ip)"


sub varflags() {
  my var="${1:-""}"
  read out <<<$(declare -p "$var" )
  [[ $out =~ /^declare.*=.*$/ ]] || die "no such variable"
  out="${out%% +([^-])=*}"
  out="${out#declare }"
  [[ ${out:0:1} == - ]] || { echo ""; return 0 ; }
  echo "${out#-}"
}

sub isarray() {
  my name="${1:-""}"
  flags=$(varflags $name)
  [[ $flags =~ a ]] && return 0
  return 1
}

sub ipcmd () {
  my ipcmd="${1:?}"; shift; array tmpbuff
  my outbuff="${2:-tmpbuff}"
}

sysfs=/sys
sysnet=$sysfs/class/net
sys_modules=$sysfs/module

sub rev () {
  (($#==0)) && { echo ""; return 0 ;}
  my element=${1:?}; shift;
  (($#==0)) && { echo "$element"; return 0;}
  echo "$(rev "$@") $element"
}

sub rename_if () {
  my old_name=${1:?} new_name=${2:?}
  echo ip link set name "$new_name" dev "$old_name"
}


sub down_if () {
  my if_name=${1:?}
  echo ip link set down dev "$if_name"
}


sub set_links_down() {# can't operate on up links
  down_if eth2 down
  down_if eth3 down
  down_if eth4 down
  down_if eth5 down
}


map act_hw2if=()  #actual values (to be read in)
map act_if2hw=()
map XIF=()#tmp array to hold exchanged IF's



##inline data (should be in external file)
map hw2if=( [00:15:17:bf:be:b2]=eth0  [00:15:17:bf:be:b3]=eth1
[00:26:b9:48:71:e2]=eth2  [00:26:b9:48:71:e4]=eth3
[a0:36:9f:15:c9:c0]=eth4  [a0:36:9f:15:c9:c2]=eth5 )

map if2hw=( [eth0]=00:15:17:bf:be:b2  [eth1]=00:15:17:bf:be:b3
[eth2]=00:26:b9:48:71:e2  [eth3]=00:26:b9:48:71:e4
[eth4]=a0:36:9f:15:c9:c0  [eth5]=a0:36:9f:15:c9:c2 )
#


#needed_drivers=(e1000e bnx2 ixgbe bonding)
needed_drivers=(e1000e bnx2 ixgbe)

sub vrfy_drivers () {
  int errors=0;
  for i in ${needed_drivers[@]} ; do
if [[ ! -d $sys_modules/$i ]]; then
  modprobe "$i" || {
warn "Module $i is not in kernel and can't be loaded"
errors+=1