make_variable_value (var, value, flags)
     SHELL_VAR *var;
     char *value;
     int flags;
{
  char *retval, *oval;
  intmax_t lval, rval;
  int expok, olen, op;

  /* If this variable has had its type set to integer (via `declare -i'),
     then do expression evaluation on it and store the result.  The
     functions in expr.c (evalexp()) and bind_int_variable() are responsible
     for turning off the integer flag if they don't want further
     evaluation done. */
  if (integer_p (var))
    {
      if (flags & ASS_APPEND)
	{
	  oval = value_cell (var);
	  lval = evalexp (oval, &expok);	/* ksh93 seems to do this */
	  if (expok == 0)
	    {
	      top_level_cleanup ();
	      jump_to_top_level (DISCARD);
	    }
	}
      rval = evalexp (value, &expok);
      if (expok == 0)
	{
	  top_level_cleanup ();
	  jump_to_top_level (DISCARD);
	}
      if (flags & ASS_APPEND)
	rval += lval;
      retval = itos (rval);
    }
#if defined (CASEMOD_ATTRS)
  else if (capcase_p (var) || uppercase_p (var) || lowercase_p (var))
    {
      if (flags & ASS_APPEND)
	{
	  oval = get_variable_value (var);
	  if (oval == 0)	/* paranoia */
	    oval = "";
	  olen = STRLEN (oval);
	  retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
	  strcpy (retval, oval);
	  if (value)
	    strcpy (retval+olen, value);
	}
      else if (*value)
	retval = savestring (value);
      else
	{
	  retval = (char *)xmalloc (1);
	  retval[0] = '\0';
	}
      op = capcase_p (var) ? CASE_CAPITALIZE
			 : (uppercase_p (var) ? CASE_UPPER : CASE_LOWER);
      oval = sh_modcase (retval, (char *)0, op);
      free (retval);
      retval = oval;
    }
#endif /* CASEMOD_ATTRS */
  else if (value)
    {
      if (flags & ASS_APPEND)
	{
	  oval = get_variable_value (var);
	  if (oval == 0)	/* paranoia */
	    oval = "";
	  olen = STRLEN (oval);
	  retval = (char *)xmalloc (olen + (value ? STRLEN (value) : 0) + 1);
	  strcpy (retval, oval);
	  if (value)
	    strcpy (retval+olen, value);
	}
      else if (*value)
	retval = savestring (value);
      else
	{
	  retval = (char *)xmalloc (1);
	  retval[0] = '\0';
	}
    }
  else
    retval = (char *)NULL;

  return retval;
}

commit bash-20120224 snapshot


cpl_reap ()
{
  struct cpelement *p, *next, *nh, *nt;

  /* Build a new list by removing dead coprocs and fix up the coproc_list
     pointers when done. */
  nh = nt = next = (struct cpelement *)0;
  for (p = coproc_list.head; p; p = next)
    {
      next = p->next;
      if (p->coproc->c_flags & COPROC_DEAD)
	{
	  coproc_list.ncoproc--;	/* keep running count, fix up pointers later */

#if defined (DEBUG)
	  itrace("cpl_reap: deleting %d", p->coproc->c_pid);
#endif

	  coproc_dispose (p->coproc);
	  cpe_dispose (p);
	}
      else if (nh == 0)
	nh = nt = p;
      else
	{
	  nt->next = p;
	  nt = nt->next;
	}
    }

  if (coproc_list.ncoproc == 0)
    coproc_list.head = coproc_list.tail = 0;
  else
    {
      if (nt)
        nt->next = 0;
      coproc_list.head = nh;
      coproc_list.tail = nt;
      if (coproc_list.ncoproc == 1)
	coproc_list.tail = coproc_list.head;		/* just to make sure */
    }
}

commit bash-20120224 snapshot


find_function (name)
     const char *name;
{
  return (hash_lookup (name, shell_functions));
}

commit bash-20120224 snapshot


cpe_alloc (cp)
     Coproc *cp;
{
  struct cpelement *cpe;

  cpe = (struct cpelement *)xmalloc (sizeof (struct cpelement));
  cpe->coproc = cp;
  cpe->next = (struct cpelement *)0;
  return cpe;
}

commit bash-20120224 snapshot


find_global_variable (name)
     const char *name;
{
  SHELL_VAR *var;

  var = var_lookup (name, global_variables);

  if (var == 0)
    return ((SHELL_VAR *)NULL);

  return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
}

commit bash-20120224 snapshot


visible_array_vars (var)
     SHELL_VAR *var;
{
  return (invisible_p (var) == 0 && array_p (var));
}

commit bash-20120224 snapshot


sh_un_double_quote (string)
     char *string;
{
  register int c, pass_next;
  char *result, *r, *s;

  r = result = (char *)xmalloc (strlen (string) + 1);

  for (pass_next = 0, s = string; s && (c = *s); s++)
    {
      if (pass_next)
	{
	  *r++ = c;
	  pass_next = 0;
	  continue;
	}
      if (c == '\\' && (sh_syntaxtab[(unsigned char) s[1]] & CBSDQUOTE))
	{
	  pass_next = 1;
	  continue;
	}
      *r++ = c;
    }

  *r = '\0';
  return result;
}

commit bash-20120224 snapshot


execute_if_command (if_command)
     IF_COM *if_command;
{
  int return_value, save_line_number;

  save_line_number = line_number;
  if_command->test->flags |= CMD_IGNORE_RETURN;
  return_value = execute_command (if_command->test);
  line_number = save_line_number;

  if (return_value == EXECUTION_SUCCESS)
    {
      QUIT;

      if (if_command->true_case && (if_command->flags & CMD_IGNORE_RETURN))
	if_command->true_case->flags |= CMD_IGNORE_RETURN;

      return (execute_command (if_command->true_case));
    }
  else
    {
      QUIT;

      if (if_command->false_case && (if_command->flags & CMD_IGNORE_RETURN))
	if_command->false_case->flags |= CMD_IGNORE_RETURN;

      return (execute_command (if_command->false_case));
    }
}

commit bash-20120224 snapshot


sv_ignoreeof (name)
     char *name;
{
  SHELL_VAR *tmp_var;
  char *temp;

  eof_encountered = 0;

  tmp_var = find_variable (name);
  ignoreeof = tmp_var != 0;
  temp = tmp_var ? value_cell (tmp_var) : (char *)NULL;
  if (temp)
    eof_encountered_limit = (*temp && all_digits (temp)) ? atoi (temp) : 10;
  set_shellopts ();	/* make sure `ignoreeof' is/is not in $SHELLOPTS */
}

commit bash-20120224 snapshot


push_args (list)
     WORD_LIST *list;
{
#if defined (ARRAY_VARS) && defined (DEBUGGER)
  SHELL_VAR *bash_argv_v, *bash_argc_v;
  ARRAY *bash_argv_a, *bash_argc_a;
  WORD_LIST *l;
  arrayind_t i;
  char *t;

  GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
  GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);

  for (l = list, i = 0; l; l = l->next, i++)
    array_push (bash_argv_a, l->word->word);

  t = itos (i);
  array_push (bash_argc_a, t);
  free (t);
#endif /* ARRAY_VARS && DEBUGGER */
}

commit bash-20120224 snapshot


coproc_dispose (cp)
     struct coproc *cp;
{
  if (cp == 0)
    return;

  coproc_unsetvars (cp);
  FREE (cp->c_name);
  coproc_close (cp);
#if MULTIPLE_COPROCS
  coproc_free (cp);
#else
  coproc_init (cp);
#endif
}

commit bash-20120224 snapshot


dispose_fd_bitmap (fdbp)
     struct fd_bitmap *fdbp;
{
  FREE (fdbp->bitmap);
  free (fdbp);
}

commit bash-20120224 snapshot


get_name_for_error ()
{
  char *name;
#if defined (ARRAY_VARS)
  SHELL_VAR *bash_source_v;
  ARRAY *bash_source_a;
#endif

  name = (char *)NULL;
  if (interactive_shell == 0)
    {
#if defined (ARRAY_VARS)
      bash_source_v = find_variable ("BASH_SOURCE");
      if (bash_source_v && array_p (bash_source_v) &&
	  (bash_source_a = array_cell (bash_source_v)))
	name = array_reference (bash_source_a, 0);
      if (name == 0 || *name == '\0')	/* XXX - was just name == 0 */
#endif
	name = dollar_vars[0];
    }
  if (name == 0 && shell_name && *shell_name)
    name = base_pathname (shell_name);
  if (name == 0)
#if defined (PROGRAM)
    name = PROGRAM;
#else
    name = "bash";
#endif

  return (name);
}

commit bash-20120224 snapshot


parser_error (lineno, format, va_alist)
     int lineno;
     const char *format;
     va_dcl
#endif
{
  va_list args;
  char *ename, *iname;

  ename = get_name_for_error ();
  iname = yy_input_name ();

  if (interactive)
    fprintf (stderr, "%s: ", ename);
  else if (interactive_shell)
    fprintf (stderr, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : _(" line "), lineno);
  else if (STREQ (ename, iname))
    fprintf (stderr, "%s:%s%d: ", ename, gnu_error_format ? "" : _(" line "), lineno);
  else
    fprintf (stderr, "%s: %s:%s%d: ", ename, iname, gnu_error_format ? "" : _(" line "), lineno);

  SH_VA_START (args, format);

  vfprintf (stderr, format, args);
  fprintf (stderr, "\n");

  va_end (args);

  if (exit_immediately_on_error)
    exit_shell (last_command_exit_value = 2);
}

commit bash-20120224 snapshot


all_array_variables ()
{
  return (vapply (visible_array_vars));
}

commit bash-20120224 snapshot


stub_charset ()
{
  char *locale, *s, *t;

  locale = get_locale_var ("LC_CTYPE");
  if (locale == 0 || *locale == 0)
    {
      strcpy (charsetbuf, "ASCII");
      return charsetbuf;
    }
  s = strrchr (locale, '.');
  if (s)
    {
      strcpy (charsetbuf, s+1);
      t = strchr (charsetbuf, '@');
      if (t)
	*t = 0;
      return charsetbuf;
    }
  strcpy (charsetbuf, locale);
  return charsetbuf;
}

commit bash-20120224 snapshot


sort_variables (array)
     SHELL_VAR **array;
{
  qsort (array, strvec_len ((char **)array), sizeof (SHELL_VAR *), (QSFUNC *)qsort_var_comp);
}

commit bash-20120224 snapshot


find_tempenv_variable (name)
     const char *name;
{
  return (temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL);
}

commit bash-20120224 snapshot


internal_error (format, va_alist)
     const char *format;
     va_dcl
#endif
{
  va_list args;

  error_prolog (1);

  SH_VA_START (args, format);

  vfprintf (stderr, format, args);
  fprintf (stderr, "\n");

  va_end (args);
}

commit bash-20120224 snapshot


make_funcname_visible (on_or_off)
     int on_or_off;
{
  SHELL_VAR *v;

  v = find_variable ("FUNCNAME");
  if (v == 0 || v->dynamic_value == 0)
    return;

  if (on_or_off)
    VUNSETATTR (v, att_invisible);
  else
    VSETATTR (v, att_invisible);
}

commit bash-20120224 snapshot


cpe_dispose (cpe)
      struct cpelement *cpe;
{
  free (cpe);
}

commit bash-20120224 snapshot


do_piping (pipe_in, pipe_out)
     int pipe_in, pipe_out;
{
  if (pipe_in != NO_PIPE)
    {
      if (dup2 (pipe_in, 0) < 0)
	dup_error (pipe_in, 0);
      if (pipe_in > 0)
	close (pipe_in);
#ifdef __CYGWIN__
      /* Let stdio know the fd may have changed from text to binary mode. */
      freopen (NULL, "r", stdin);
#endif /* __CYGWIN__ */
    }
  if (pipe_out != NO_PIPE)
    {
      if (pipe_out != REDIRECT_BOTH)
	{
	  if (dup2 (pipe_out, 1) < 0)
	    dup_error (pipe_out, 1);
	  if (pipe_out == 0 || pipe_out > 1)
	    close (pipe_out);
	}
      else
	{
	  if (dup2 (1, 2) < 0)
	    dup_error (1, 2);
	}
#ifdef __CYGWIN__
      /* Let stdio know the fd may have changed from text to binary mode, and
	 make sure to preserve stdout line buffering. */
      freopen (NULL, "w", stdout);
      sh_setlinebuf (stdout);
#endif /* __CYGWIN__ */
    }
}

commit bash-20120224 snapshot


vlist_alloc (nentries)
     int nentries;
{
  VARLIST  *vlist;

  vlist = (VARLIST *)xmalloc (sizeof (VARLIST));
  vlist->list = (SHELL_VAR **)xmalloc ((nentries + 1) * sizeof (SHELL_VAR *));
  vlist->list_size = nentries;
  vlist->list_len = 0;
  vlist->list[0] = (SHELL_VAR *)NULL;

  return vlist;
}

commit bash-20120224 snapshot


unbind_function_def (name)
     const char *name;
{
  BUCKET_CONTENTS *elt;
  FUNCTION_DEF *funcdef;

  elt = hash_remove (name, shell_function_defs, 0);

  if (elt == 0)
    return -1;

  funcdef = (FUNCTION_DEF *)elt->data;
  if (funcdef)
    dispose_function_def (funcdef);

  free (elt->key);
  free (elt);

  return 0;
}

commit bash-20120224 snapshot


update_export_env_inplace (env_prefix, preflen, value)
     char *env_prefix;
     int preflen;
     char *value;
{
  char *evar;

  evar = (char *)xmalloc (STRLEN (value) + preflen + 1);
  strcpy (evar, env_prefix);
  if (value)
    strcpy (evar + preflen, value);
  export_env = add_or_supercede_exported_var (evar, 0);
}

commit bash-20120224 snapshot


propagate_temp_var (data)
     PTR_T data;
{
  SHELL_VAR *var;

  var = (SHELL_VAR *)data;
  if (tempvar_p (var) && (var->attributes & att_propagate))
    push_temp_var (data);
  else
    {
      if (find_special_var (var->name) >= 0)
	tempvar_list[tvlist_ind++] = savestring (var->name);
      dispose_variable (var);
    }
}

commit bash-20120224 snapshot


print_select_list (list, list_len, max_elem_len, indices_len)
     WORD_LIST *list;
     int list_len, max_elem_len, indices_len;
{
  int ind, row, elem_len, pos, cols, rows;
  int first_column_indices_len, other_indices_len;

  if (list == 0)
    {
      putc ('\n', stderr);
      return;
    }

  cols = max_elem_len ? COLS / max_elem_len : 1;
  if (cols == 0)
    cols = 1;
  rows = list_len ? list_len / cols + (list_len % cols != 0) : 1;
  cols = list_len ? list_len / rows + (list_len % rows != 0) : 1;

  if (rows == 1)
    {
      rows = cols;
      cols = 1;
    }

  first_column_indices_len = NUMBER_LEN (rows);
  other_indices_len = indices_len;

  for (row = 0; row < rows; row++)
    {
      ind = row;
      pos = 0;
      while (1)
	{
	  indices_len = (pos == 0) ? first_column_indices_len : other_indices_len;
	  elem_len = print_index_and_element (indices_len, ind + 1, list);
	  elem_len += indices_len + RP_SPACE_LEN;
	  ind += rows;
	  if (ind >= list_len)
	    break;
	  indent (pos + elem_len, pos + max_elem_len);
	  pos += max_elem_len;
	}
      putc ('\n', stderr);
    }
}

commit bash-20120224 snapshot


uidset ()
{
  char buff[INT_STRLEN_BOUND(uid_t) + 1], *b;
  register SHELL_VAR *v;

  b = inttostr (current_user.uid, buff, sizeof (buff));
  v = find_variable ("UID");
  if (v == 0)
    {
      v = bind_variable ("UID", b, 0);
      VSETATTR (v, (att_readonly | att_integer));
    }

  if (current_user.euid != current_user.uid)
    b = inttostr (current_user.euid, buff, sizeof (buff));

  v = find_variable ("EUID");
  if (v == 0)
    {
      v = bind_variable ("EUID", b, 0);
      VSETATTR (v, (att_readonly | att_integer));
    }
}

commit bash-20120224 snapshot


main()
{

union {
	long int l;
	char c[sizeof(long int)];
} u;
	int x0, x1, x2, x3;

	u.l = 1;
	x0 = u.c[0];
	x3 = u.c[sizeof (long int) - 1];
	printf ("x0 = %d x3 = %d (%s)\n", x0, x3, x3 == 1 ? "bigendian" : "littleendian");
	x0 = u.l >> 24;
	x1 = u.l >> 16;
	x2 = u.l >> 8;
	x3 = u.l & 0xff;
	printf ("x0:x3: %d %d %d %d\n", x0, x1, x2, x3);
}

commit bash-20120224 snapshot


getcoprocbyname (name)
     const char *name;
{
#if MULTIPLE_COPROCS
  struct cpelement *p;

  p = cpl_searchbyname (name);
  return (p ? p->coproc : 0);
#else
  return ((sh_coproc.c_name && STREQ (sh_coproc.c_name, name)) ? &sh_coproc : 0);
#endif
}

commit bash-20120224 snapshot


vapply (func)
     sh_var_map_func_t *func;
{
  SHELL_VAR **list;

  list = map_over (func, shell_variables);
  if (list /* && posixly_correct */)
    sort_variables (list);
  return (list);
}

commit bash-20120224 snapshot


visible_var (var)
     SHELL_VAR *var;
{
  return (invisible_p (var) == 0);
}

commit bash-20120224 snapshot


copy_variable (var)
     SHELL_VAR *var;
{
  SHELL_VAR *copy = (SHELL_VAR *)NULL;

  if (var)
    {
      copy = (SHELL_VAR *)xmalloc (sizeof (SHELL_VAR));

      copy->attributes = var->attributes;
      copy->name = savestring (var->name);

      if (function_p (var))
	var_setfunc (copy, copy_command (function_cell (var)));
#if defined (ARRAY_VARS)
      else if (array_p (var))
	var_setarray (copy, array_copy (array_cell (var)));
      else if (assoc_p (var))
	var_setassoc (copy, assoc_copy (assoc_cell (var)));
#endif
      else if (value_cell (var))
	var_setvalue (copy, savestring (value_cell (var)));
      else
	var_setvalue (copy, (char *)NULL);

      copy->dynamic_value = var->dynamic_value;
      copy->assign_func = var->assign_func;

      copy->exportstr = COPY_EXPORTSTR (var);

      copy->context = var->context;
    }
  return (copy);
}

commit bash-20120224 snapshot


make_local_variable (name)
     const char *name;
{
  SHELL_VAR *new_var, *old_var;
  VAR_CONTEXT *vc;
  int was_tmpvar;
  char *tmp_value;

  /* local foo; local foo;  is a no-op. */
  old_var = find_variable (name);
  if (old_var && local_p (old_var) && old_var->context == variable_context)
    {
      VUNSETATTR (old_var, att_invisible);
      return (old_var);
    }

  was_tmpvar = old_var && tempvar_p (old_var);
  if (was_tmpvar)
    tmp_value = value_cell (old_var);

  for (vc = shell_variables; vc; vc = vc->down)
    if (vc_isfuncenv (vc) && vc->scope == variable_context)
      break;

  if (vc == 0)
    {
      internal_error (_("make_local_variable: no function context at current scope"));
      return ((SHELL_VAR *)NULL);
    }
  else if (vc->table == 0)
    vc->table = hash_create (TEMPENV_HASH_BUCKETS);

  /* Since this is called only from the local/declare/typeset code, we can
     call builtin_error here without worry (of course, it will also work
     for anything that sets this_command_name).  Variables with the `noassign'
     attribute may not be made local.  The test against old_var's context
     level is to disallow local copies of readonly global variables (since I
     believe that this could be a security hole).  Readonly copies of calling
     function local variables are OK. */
  if (old_var && (noassign_p (old_var) ||
		 (readonly_p (old_var) && old_var->context == 0)))
    {
      if (readonly_p (old_var))
	sh_readonly (name);
      return ((SHELL_VAR *)NULL);
    }

  if (old_var == 0)
    new_var = make_new_variable (name, vc->table);
  else
    {
      new_var = make_new_variable (name, vc->table);

      /* If we found this variable in one of the temporary environments,
	 inherit its value.  Watch to see if this causes problems with
	 things like `x=4 local x'. */
      if (was_tmpvar)
	var_setvalue (new_var, savestring (tmp_value));

      new_var->attributes = exported_p (old_var) ? att_exported : 0;
    }

  vc->flags |= VC_HASLOCAL;

  new_var->context = variable_context;
  VSETATTR (new_var, att_local);

  if (ifsname (name))
    setifs (new_var);

  return (new_var);
}

commit bash-20120224 snapshot


assign_lineno (var, value, unused, key)
     SHELL_VAR *var;
     char *value;
     arrayind_t unused;
     char *key;
{
  intmax_t new_value;

  if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
    new_value = 0;
  line_number = line_number_base = new_value;
  return var;
}

commit bash-20120224 snapshot


commit bash-20120224 snapshot


coproc_fdsave (cp)
     struct coproc *cp;
{
  cp->c_rsave = cp->c_rfd;
  cp->c_wsave = cp->c_wfd;
}

commit bash-20120224 snapshot


sh_backslash_quote_for_double_quotes (string)
     char *string;
{
  unsigned char c;
  char *result, *r, *s;

  result = (char *)xmalloc (2 * strlen (string) + 1);

  for (r = result, s = string; s && (c = *s); s++)
    {
      if (sh_syntaxtab[c] & CBSDQUOTE)
	*r++ = '\\';
      /* I should probably add flags for these to sh_syntaxtab[] */
      else if (c == CTLESC || c == CTLNUL)
	*r++ = CTLESC;		/* could be '\\'? */

      *r++ = c;
    }

  *r = '\0';
  return (result);
}

commit bash-20120224 snapshot


null_array_assign (self, value, ind, key)
     SHELL_VAR *self;
     char *value;
     arrayind_t ind;
     char *key;
{
  return (self);
}

commit bash-20120224 snapshot


cpl_delete (pid)
     pid_t pid;
{
  struct cpelement *prev, *p;

  for (prev = p = coproc_list.head; p; prev = p, p = p->next)
    if (p->coproc->c_pid == pid)
      {
        prev->next = p->next;	/* remove from list */
        break;
      }

  if (p == 0)
    return 0;		/* not found */

#if defined (DEBUG)
  itrace("cpl_delete: deleting %d", pid);
#endif

  /* Housekeeping in the border cases. */
  if (p == coproc_list.head)
    coproc_list.head = coproc_list.head->next;
  else if (p == coproc_list.tail)
    coproc_list.tail = prev;

  coproc_list.ncoproc--;
  if (coproc_list.ncoproc == 0)
    coproc_list.head = coproc_list.tail = 0;
  else if (coproc_list.ncoproc == 1)
    coproc_list.tail = coproc_list.head;		/* just to make sure */

  return (p);
}

commit bash-20120224 snapshot


coproc_unsetvars (cp)
     struct coproc *cp;
{
  int l;
  char *namevar;

  if (cp->c_name == 0)
    return;

  l = strlen (cp->c_name);
  namevar = xmalloc (l + 16);

  sprintf (namevar, "%s_PID", cp->c_name);
  unbind_variable (namevar);

#if defined (ARRAY_VARS)
  unbind_variable (cp->c_name);
#else
  sprintf (namevar, "%s_READ", cp->c_name);
  unbind_variable (namevar);
  sprintf (namevar, "%s_WRITE", cp->c_name);
  unbind_variable (namevar);
#endif

  free (namevar);
}

commit bash-20120224 snapshot


initialize_subshell ()
{
#if defined (ALIAS)
  /* Forget about any aliases that we knew of.  We are in a subshell. */
  delete_all_aliases ();
#endif /* ALIAS */

#if defined (HISTORY)
  /* Forget about the history lines we have read.  This is a non-interactive
     subshell. */
  history_lines_this_session = 0;
#endif

#if defined (JOB_CONTROL)
  /* Forget about the way job control was working. We are in a subshell. */
  without_job_control ();
  set_sigchld_handler ();
  init_job_stats ();
#endif /* JOB_CONTROL */

  /* Reset the values of the shell flags and options. */
  reset_shell_flags ();
  reset_shell_options ();
  reset_shopt_options ();

  /* Zero out builtin_env, since this could be a shell script run from a
     sourced file with a temporary environment supplied to the `source/.'
     builtin.  Such variables are not supposed to be exported (empirical
     testing with sh and ksh).  Just throw it away; don't worry about a
     memory leak. */
  if (vc_isbltnenv (shell_variables))
    shell_variables = shell_variables->down;

  clear_unwind_protect_list (0);
  /* XXX -- are there other things we should be resetting here? */
  parse_and_execute_level = 0;		/* nothing left to restore it */

  /* We're no longer inside a shell function. */
  variable_context = return_catch_flag = funcnest = 0;

  executing_list = 0;		/* XXX */

  /* If we're not interactive, close the file descriptor from which we're
     reading the current shell script. */
  if (interactive_shell == 0)
    unset_bash_input (0);
}

commit bash-20120224 snapshot


make_vers_array ()
{
  SHELL_VAR *vv;
  ARRAY *av;
  char *s, d[32], b[INT_STRLEN_BOUND(int) + 1];

  unbind_variable ("BASH_VERSINFO");

  vv = make_new_array_variable ("BASH_VERSINFO");
  av = array_cell (vv);
  strcpy (d, dist_version);
  s = strchr (d, '.');
  if (s)
    *s++ = '\0';
  array_insert (av, 0, d);
  array_insert (av, 1, s);
  s = inttostr (patch_level, b, sizeof (b));
  array_insert (av, 2, s);
  s = inttostr (build_version, b, sizeof (b));
  array_insert (av, 3, s);
  array_insert (av, 4, release_status);
  array_insert (av, 5, MACHTYPE);

  VSETATTR (vv, att_readonly);
}

commit bash-20120224 snapshot


delete_all_contexts (vcxt)
     VAR_CONTEXT *vcxt;
{
  VAR_CONTEXT *v, *t;

  for (v = vcxt; v != global_variables; v = t)
    {
      t = v->down;
      dispose_var_context (v);
    }

  delete_all_variables (global_variables->table);
  shell_variables = global_variables;
}

commit bash-20120224 snapshot


all_shell_variables ()
{
  return (vapply ((sh_var_map_func_t *)NULL));
}

commit bash-20120224 snapshot


dispose_saved_dollar_vars ()
{
  if (!dollar_arg_stack || dollar_arg_stack_index == 0)
    return;

  dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
  dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
}

commit bash-20120224 snapshot


flatten (var_hash_table, func, vlist, flags)
     HASH_TABLE *var_hash_table;
     sh_var_map_func_t *func;
     VARLIST *vlist;
     int flags;
{
  register int i;
  register BUCKET_CONTENTS *tlist;
  int r;
  SHELL_VAR *var;

  if (var_hash_table == 0 || (HASH_ENTRIES (var_hash_table) == 0) || (vlist == 0 && func == 0))
    return;

  for (i = 0; i < var_hash_table->nbuckets; i++)
    {
      for (tlist = hash_items (i, var_hash_table); tlist; tlist = tlist->next)
	{
	  var = (SHELL_VAR *)tlist->data;

	  r = func ? (*func) (var) : 1;
	  if (r && vlist)
	    vlist_add (vlist, var, flags);
	}
    }
}

commit bash-20120224 snapshot


all_shell_functions ()
{
  return (fapply ((sh_var_map_func_t *)NULL));
}

commit bash-20120224 snapshot


close_fd_bitmap (fdbp)
     struct fd_bitmap *fdbp;
{
  register int i;

  if (fdbp)
    {
      for (i = 0; i < fdbp->size; i++)
	if (fdbp->bitmap[i])
	  {
	    close (i);
	    fdbp->bitmap[i] = 0;
	  }
    }
}

commit bash-20120224 snapshot


export_environment_candidate (var)
     SHELL_VAR *var;
{
  return (exported_p (var) && (invisible_p (var) == 0 || imported_p (var)));
}

commit bash-20120224 snapshot


cpl_search (pid)
     pid_t pid;
{
  struct cpelement *cpe;

  for (cpe = coproc_list.head ; cpe; cpe = cpe->next)
    if (cpe->coproc->c_pid == pid)
      return cpe;
  return (struct cpelement *)NULL;
}

commit bash-20120224 snapshot


valid_exportstr (v)
     SHELL_VAR *v;
{
  char *s;

  s = v->exportstr;
  if (s == 0)
    {
      internal_error (_("%s has null exportstr"), v->name);
      return (0);
    }
  if (legal_variable_starter ((unsigned char)*s) == 0)
    {
      internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
      return (0);
    }
  for (s = v->exportstr + 1; s && *s; s++)
    {
      if (*s == '=')
	break;
      if (legal_variable_char ((unsigned char)*s) == 0)
	{
	  internal_error (_("invalid character %d in exportstr for %s"), *s, v->name);
	  return (0);
	}
    }
  if (*s != '=')
    {
      internal_error (_("no `=' in exportstr for %s"), v->name);
      return (0);
    }
  return (1);
}

commit bash-20120224 snapshot


file_error (filename)
     const char *filename;
{
  report_error ("%s: %s", filename, strerror (errno));
}

commit bash-20120224 snapshot


initialize_shell_level ()
{
  adjust_shell_level (1);
}

commit bash-20120224 snapshot


sh_get_env_value (v)
     const char *v;
{
  return get_string_value (v);
}

commit bash-20120224 snapshot


execute_shell_function (var, words)
     SHELL_VAR *var;
     WORD_LIST *words;
{
  int ret;
  struct fd_bitmap *bitmap;

  bitmap = new_fd_bitmap (FD_BITMAP_DEFAULT_SIZE);
  begin_unwind_frame ("execute-shell-function");
  add_unwind_protect (dispose_fd_bitmap, (char *)bitmap);

  ret = execute_function (var, words, 0, bitmap, 0, 0);

  dispose_fd_bitmap (bitmap);
  discard_unwind_frame ("execute-shell-function");

  return ret;
}

commit bash-20120224 snapshot


init_seconds_var ()
{
  SHELL_VAR *v;

  v = find_variable ("SECONDS");
  if (v)
    {
      if (legal_number (value_cell(v), &seconds_value_assigned) == 0)
	seconds_value_assigned = 0;
    }
  INIT_DYNAMIC_VAR ("SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds);
  return v;
}

commit bash-20120224 snapshot


map_over_funcs (function)
     sh_var_map_func_t *function;
{
  VARLIST *vlist;
  SHELL_VAR **ret;

  if (shell_functions == 0 || HASH_ENTRIES (shell_functions) == 0)
    return ((SHELL_VAR **)NULL);

  vlist = vlist_alloc (HASH_ENTRIES (shell_functions));

  flatten (shell_functions, function, vlist, 0);

  ret = vlist->list;
  free (vlist);
  return ret;
}

commit bash-20120224 snapshot


make_local_assoc_variable (name)
     char *name;
{
  SHELL_VAR *var;
  HASH_TABLE *hash;

  var = make_local_variable (name);
  if (var == 0 || assoc_p (var))
    return var;

  dispose_variable_value (var);
  hash = assoc_create (0);

  var_setassoc (var, hash);
  VSETATTR (var, att_assoc);
  return var;
}

commit bash-20120224 snapshot


commit bash-20120224 snapshot


put_command_name_into_env (command_name)
     char *command_name;
{
  update_export_env_inplace ("_=", 2, command_name);
}

commit bash-20120224 snapshot


pop_context ()
{
  pop_dollar_vars ();
  variable_context--;
  pop_var_context ();

  sv_ifs ("IFS");		/* XXX here for now */
}

commit bash-20120224 snapshot


find_variable (name)
     const char *name;
{
  return (find_variable_internal (name, (expanding_redir == 0 && (assigning_in_environment || executing_builtin))));
}

commit bash-20120224 snapshot


initialize_dynamic_variables ()
{
  SHELL_VAR *v;

  v = init_seconds_var ();

  INIT_DYNAMIC_VAR ("BASH_COMMAND", (char *)NULL, get_bash_command, (sh_var_assign_func_t *)NULL);
  INIT_DYNAMIC_VAR ("BASH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell);

  INIT_DYNAMIC_VAR ("RANDOM", (char *)NULL, get_random, assign_random);
  VSETATTR (v, att_integer);
  INIT_DYNAMIC_VAR ("LINENO", (char *)NULL, get_lineno, assign_lineno);
  VSETATTR (v, att_integer);

  INIT_DYNAMIC_VAR ("BASHPID", (char *)NULL, get_bashpid, null_assign);
  VSETATTR (v, att_integer|att_readonly);

#if defined (HISTORY)
  INIT_DYNAMIC_VAR ("HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL);
  VSETATTR (v, att_integer);
#endif

#if defined (READLINE)
  INIT_DYNAMIC_VAR ("COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks);
#endif

#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)
  v = init_dynamic_array_var ("DIRSTACK", get_dirstack, assign_dirstack, 0);
#endif /* PUSHD_AND_POPD && ARRAY_VARS */

#if defined (ARRAY_VARS)
  v = init_dynamic_array_var ("GROUPS", get_groupset, null_array_assign, att_noassign);

#  if defined (DEBUGGER)
  v = init_dynamic_array_var ("BASH_ARGC", get_self, null_array_assign, att_noassign|att_nounset);
  v = init_dynamic_array_var ("BASH_ARGV", get_self, null_array_assign, att_noassign|att_nounset);
#  endif /* DEBUGGER */
  v = init_dynamic_array_var ("BASH_SOURCE", get_self, null_array_assign, att_noassign|att_nounset);
  v = init_dynamic_array_var ("BASH_LINENO", get_self, null_array_assign, att_noassign|att_nounset);

  v = init_dynamic_assoc_var ("BASH_CMDS", get_hashcmd, assign_hashcmd, att_nofree);
#  if defined (ALIAS)
  v = init_dynamic_assoc_var ("BASH_ALIASES", get_aliasvar, assign_aliasvar, att_nofree);
#  endif
#endif

  v = init_funcname_var ();
}

commit bash-20120224 snapshot


print_func_list (list)
     register SHELL_VAR **list;
{
  register int i;
  register SHELL_VAR *var;

  for (i = 0; list && (var = list[i]); i++)
    {
      printf ("%s ", var->name);
      print_var_function (var);
      printf ("\n");
    }
}

commit bash-20120224 snapshot


get_bashpid (var)
     SHELL_VAR *var;
{
  int pid;
  char *p;

  pid = getpid ();
  p = itos (pid);

  FREE (value_cell (var));
  VSETATTR (var, att_integer|att_readonly);
  var_setvalue (var, p);
  return (var);
}

commit bash-20120224 snapshot


all_local_variables ()
{
  VARLIST *vlist;
  SHELL_VAR **ret;
  VAR_CONTEXT *vc;

  vc = shell_variables;
  for (vc = shell_variables; vc; vc = vc->down)
    if (vc_isfuncenv (vc) && vc->scope == variable_context)
      break;

  if (vc == 0)
    {
      internal_error (_("all_local_variables: no function context at current scope"));
      return (SHELL_VAR **)NULL;
    }
  if (vc->table == 0 || HASH_ENTRIES (vc->table) == 0 || vc_haslocals (vc) == 0)
    return (SHELL_VAR **)NULL;

  vlist = vlist_alloc (HASH_ENTRIES (vc->table));

  flatten (vc->table, variable_in_context, vlist, 0);

  ret = vlist->list;
  free (vlist);
  if (ret)
    sort_variables (ret);
  return ret;
}

commit bash-20120224 snapshot


print_var_function (var)
     SHELL_VAR *var;
{
  char *x;

  if (function_p (var) && var_isset (var))
    {
      x = named_function_string ((char *)NULL, function_cell(var), FUNC_MULTILINE|FUNC_EXTERNAL);
      printf ("%s", x);
    }
}

commit bash-20120224 snapshot


coproc_free (cp)
     struct coproc *cp;
{
  free (cp);
}

commit bash-20120224 snapshot


execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
     SIMPLE_COM *simple_command;
     int pipe_in, pipe_out, async;
     struct fd_bitmap *fds_to_close;
{
  WORD_LIST *words, *lastword;
  char *command_line, *lastarg, *temp;
  int first_word_quoted, result, builtin_is_special, already_forked, dofork;
  pid_t old_last_async_pid;
  sh_builtin_func_t *builtin;
  SHELL_VAR *func;
  volatile int old_builtin, old_command_builtin;

  result = EXECUTION_SUCCESS;
  special_builtin_failed = builtin_is_special = 0;
  command_line = (char *)0;

  QUIT;

  /* If we're in a function, update the line number information. */
  if (variable_context && interactive_shell && sourcelevel == 0)
    line_number -= function_line_number;

  /* Remember what this command line looks like at invocation. */
  command_string_index = 0;
  print_simple_command (simple_command);

#if 0
  if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0)))
#else
  if (signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0)
#endif
    {
      FREE (the_printed_command_except_trap);
      the_printed_command_except_trap = the_printed_command ? savestring (the_printed_command) : (char *)0;
    }

  /* Run the debug trap before each simple command, but do it after we
     update the line number information. */
  result = run_debug_trap ();
#if defined (DEBUGGER)
  /* In debugging mode, if the DEBUG trap returns a non-zero status, we
     skip the command. */
  if (debugging_mode && result != EXECUTION_SUCCESS)
    return (EXECUTION_SUCCESS);
#endif

  first_word_quoted =
    simple_command->words ? (simple_command->words->word->flags & W_QUOTED) : 0;

  last_command_subst_pid = NO_PID;
  old_last_async_pid = last_asynchronous_pid;

  already_forked = dofork = 0;

  /* If we're in a pipeline or run in the background, set DOFORK so we
     make the child early, before word expansion.  This keeps assignment
     statements from affecting the parent shell's environment when they
     should not. */
  dofork = pipe_in != NO_PIPE || pipe_out != NO_PIPE || async;

  /* Something like `%2 &' should restart job 2 in the background, not cause
     the shell to fork here. */
  if (dofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE &&
	simple_command->words && simple_command->words->word &&
	simple_command->words->word->word &&
	(simple_command->words->word->word[0] == '%'))
    dofork = 0;

  if (dofork)
    {
      /* Do this now, because execute_disk_command will do it anyway in the
	 vast majority of cases. */
      maybe_make_export_env ();

      /* Don't let a DEBUG trap overwrite the command string to be saved with
	 the process/job associated with this child. */
      if (make_child (savestring (the_printed_command_except_trap), async) == 0)
	{
	  already_forked = 1;
	  simple_command->flags |= CMD_NO_FORK;

	  subshell_environment = SUBSHELL_FORK;
	  if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
	    subshell_environment |= SUBSHELL_PIPE;
	  if (async)
	    subshell_environment |= SUBSHELL_ASYNC;

	  /* We need to do this before piping to handle some really
	     pathological cases where one of the pipe file descriptors
	     is < 2. */
	  if (fds_to_close)
	    close_fd_bitmap (fds_to_close);

	  do_piping (pipe_in, pipe_out);
	  pipe_in = pipe_out = NO_PIPE;
#if defined (COPROCESS_SUPPORT)
	  coproc_closeall ();
#endif

	  last_asynchronous_pid = old_last_async_pid;
	}
      else
	{
	  /* Don't let simple commands that aren't the last command in a
	     pipeline change $? for the rest of the pipeline (or at all). */
	  if (pipe_out != NO_PIPE)
	    result = last_command_exit_value;
	  close_pipes (pipe_in, pipe_out);
#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD)
	  unlink_fifo_list ();
#endif
	  command_line = (char *)NULL;      /* don't free this. */
	  bind_lastarg ((char *)NULL);
	  return (result);
	}
    }

  /* If we are re-running this as the result of executing the `command'
     builtin, do not expand the command words a second time. */
  if ((simple_command->flags & CMD_INHIBIT_EXPANSION) == 0)
    {
      current_fds_to_close = fds_to_close;
      fix_assignment_words (simple_command->words);
      /* Pass the ignore return flag down to command substitutions */
      if (simple_command->flags & CMD_IGNORE_RETURN)	/* XXX */
	comsub_ignore_return++;
      words = expand_words (simple_command->words);
      if (simple_command->flags & CMD_IGNORE_RETURN)
	comsub_ignore_return--;
      current_fds_to_close = (struct fd_bitmap *)NULL;
    }
  else
    words = copy_word_list (simple_command->words);

  /* It is possible for WORDS not to have anything left in it.
     Perhaps all the words consisted of `$foo', and there was
     no variable `$foo'. */
  if (words == 0)
    {
      this_command_name = 0;
      result = execute_null_command (simple_command->redirects,
				     pipe_in, pipe_out,
				     already_forked ? 0 : async);
      if (already_forked)
	exit (result);
      else
	{
	  bind_lastarg ((char *)NULL);
	  set_pipestatus_from_exit (result);
	  return (result);
	}
    }

  lastarg = (char *)NULL;

  begin_unwind_frame ("simple-command");

  if (echo_command_at_execute)
    xtrace_print_word_list (words, 1);

  builtin = (sh_builtin_func_t *)NULL;
  func = (SHELL_VAR *)NULL;
  if ((simple_command->flags & CMD_NO_FUNCTIONS) == 0)
    {
      /* Posix.2 says special builtins are found before functions.  We
	 don't set builtin_is_special anywhere other than here, because
	 this path is followed only when the `command' builtin is *not*
	 being used, and we don't want to exit the shell if a special
	 builtin executed with `command builtin' fails.  `command' is not
	 a special builtin. */
      if (posixly_correct)
	{
	  builtin = find_special_builtin (words->word->word);
	  if (builtin)
	    builtin_is_special = 1;
	}
      if (builtin == 0)
	func = find_function (words->word->word);
    }

  /* In POSIX mode, assignment errors in the temporary environment cause a
     non-interactive shell to exit. */
  if (builtin_is_special && interactive_shell == 0 && tempenv_assign_error)
    {
      last_command_exit_value = EXECUTION_FAILURE;
      jump_to_top_level (ERREXIT);
    }

  add_unwind_protect (dispose_words, words);
  QUIT;

  /* Bind the last word in this command to "$_" after execution. */
  for (lastword = words; lastword->next; lastword = lastword->next)
    ;
  lastarg = lastword->word->word;

#if defined (JOB_CONTROL)
  /* Is this command a job control related thing? */
  if (words->word->word[0] == '%' && already_forked == 0)
    {
      this_command_name = async ? "bg" : "fg";
      last_shell_builtin = this_shell_builtin;
      this_shell_builtin = builtin_address (this_command_name);
      result = (*this_shell_builtin) (words);
      goto return_result;
    }

  /* One other possiblilty.  The user may want to resume an existing job.
     If they do, find out whether this word is a candidate for a running
     job. */
  if (job_control && already_forked == 0 && async == 0 &&
	!first_word_quoted &&
	!words->next &&
	words->word->word[0] &&
	!simple_command->redirects &&
	pipe_in == NO_PIPE &&
	pipe_out == NO_PIPE &&
	(temp = get_string_value ("auto_resume")))
    {
      int job, jflags, started_status;

      jflags = JM_STOPPED|JM_FIRSTMATCH;
      if (STREQ (temp, "exact"))
	jflags |= JM_EXACT;
      else if (STREQ (temp, "substring"))
	jflags |= JM_SUBSTRING;
      else
	jflags |= JM_PREFIX;
      job = get_job_by_name (words->word->word, jflags);
      if (job != NO_JOB)
	{
	  run_unwind_frame ("simple-command");
	  this_command_name = "fg";
	  last_shell_builtin = this_shell_builtin;
	  this_shell_builtin = builtin_address ("fg");

	  started_status = start_job (job, 1);
	  return ((started_status < 0) ? EXECUTION_FAILURE : started_status);
	}
    }
#endif /* JOB_CONTROL */

run_builtin:
  /* Remember the name of this command globally. */
  this_command_name = words->word->word;

  QUIT;

  /* This command could be a shell builtin or a user-defined function.
     We have already found special builtins by this time, so we do not
     set builtin_is_special.  If this is a function or builtin, and we
     have pipes, then fork a subshell in here.  Otherwise, just execute
     the command directly. */
  if (func == 0 && builtin == 0)
    builtin = find_shell_builtin (this_command_name);

  last_shell_builtin = this_shell_builtin;
  this_shell_builtin = builtin;

  if (builtin || func)
    {
      if (builtin)
        {
	  old_builtin = executing_builtin;
	  old_command_builtin = executing_command_builtin;
	  unwind_protect_int (executing_builtin);	/* modified in execute_builtin */
	  unwind_protect_int (executing_command_builtin);	/* ditto */
        }
      if (already_forked)
	{
	  /* reset_terminating_signals (); */	/* XXX */
	  /* Reset the signal handlers in the child, but don't free the
	     trap strings.  Set a flag noting that we have to free the
	     trap strings if we run trap to change a signal disposition. */
	  reset_signal_handlers ();
	  subshell_environment |= SUBSHELL_RESETTRAP;

	  if (async)
	    {
	      if ((simple_command->flags & CMD_STDIN_REDIR) &&
		    pipe_in == NO_PIPE &&
		    (stdin_redirects (simple_command->redirects) == 0))
		async_redirect_stdin ();
	      setup_async_signals ();
	    }

	  subshell_level++;
	  execute_subshell_builtin_or_function
	    (words, simple_command->redirects, builtin, func,
	     pipe_in, pipe_out, async, fds_to_close,
	     simple_command->flags);
	  subshell_level--;
	}
      else
	{
	  result = execute_builtin_or_function
	    (words, builtin, func, simple_command->redirects, fds_to_close,
	     simple_command->flags);
	  if (builtin)
	    {
	      if (result > EX_SHERRBASE)
		{
		  result = builtin_status (result);
		  if (builtin_is_special)
		    special_builtin_failed = 1;
		}
	      /* In POSIX mode, if there are assignment statements preceding
		 a special builtin, they persist after the builtin
		 completes. */
	      if (posixly_correct && builtin_is_special && temporary_env)
		merge_temporary_env ();
	    }
	  else		/* function */
	    {
	      if (result == EX_USAGE)
		result = EX_BADUSAGE;
	      else if (result > EX_SHERRBASE)
		result = EXECUTION_FAILURE;
	    }

	  set_pipestatus_from_exit (result);

	  goto return_result;
	}
    }

  if (autocd && interactive && words->word && is_dirname (words->word->word))
    {
      words = make_word_list (make_word ("cd"), words);
      xtrace_print_word_list (words, 0);
      goto run_builtin;
    }

  if (command_line == 0)
    command_line = savestring (the_printed_command_except_trap);

#if defined (PROCESS_SUBSTITUTION)
  if ((subshell_environment & SUBSHELL_COMSUB) && (simple_command->flags & CMD_NO_FORK) && fifos_pending() > 0)
    simple_command->flags &= ~CMD_NO_FORK;
#endif

  result = execute_disk_command (words, simple_command->redirects, command_line,
			pipe_in, pipe_out, async, fds_to_close,
			simple_command->flags);

 return_result:
  bind_lastarg (lastarg);
  FREE (command_line);
  dispose_words (words);
  if (builtin)
    {
      executing_builtin = old_builtin;
      executing_command_builtin = old_command_builtin;
    }
  discard_unwind_frame ("simple-command");
  this_command_name = (char *)NULL;	/* points to freed memory now */
  return (result);
}

commit bash-20120224 snapshot


print_formatted_time (fp, format, rs, rsf, us, usf, ss, ssf, cpu)
     FILE *fp;
     char *format;
     time_t rs;
     int rsf;
     time_t us;
     int usf;
     time_t ss;
     int ssf, cpu;
{
  int prec, lng, len;
  char *str, *s, ts[INT_STRLEN_BOUND (time_t) + sizeof ("mSS.FFFF")];
  time_t sum;
  int sum_frac;
  int sindex, ssize;

  len = strlen (format);
  ssize = (len + 64) - (len % 64);
  str = (char *)xmalloc (ssize);
  sindex = 0;

  for (s = format; *s; s++)
    {
      if (*s != '%' || s[1] == '\0')
	{
	  RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64);
	  str[sindex++] = *s;
	}
      else if (s[1] == '%')
	{
	  s++;
	  RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64);
	  str[sindex++] = *s;
	}
      else if (s[1] == 'P')
	{
	  s++;
#if 0
	  /* clamp CPU usage at 100% */
	  if (cpu > 10000)
	    cpu = 10000;
#endif
	  sum = cpu / 100;
	  sum_frac = (cpu % 100) * 10;
	  len = mkfmt (ts, 2, 0, sum, sum_frac);
	  RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64);
	  strcpy (str + sindex, ts);
	  sindex += len;
	}
      else
	{
	  prec = 3;	/* default is three places past the decimal point. */
	  lng = 0;	/* default is to not use minutes or append `s' */
	  s++;
	  if (DIGIT (*s))		/* `precision' */
	    {
	      prec = *s++ - '0';
	      if (prec > 3) prec = 3;
	    }
	  if (*s == 'l')		/* `length extender' */
	    {
	      lng = 1;
	      s++;
	    }
	  if (*s == 'R' || *s == 'E')
	    len = mkfmt (ts, prec, lng, rs, rsf);
	  else if (*s == 'U')
	    len = mkfmt (ts, prec, lng, us, usf);
	  else if (*s == 'S')
	    len = mkfmt (ts, prec, lng, ss, ssf);
	  else
	    {
	      internal_error (_("TIMEFORMAT: `%c': invalid format character"), *s);
	      free (str);
	      return;
	    }
	  RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64);
	  strcpy (str + sindex, ts);
	  sindex += len;
	}
    }

  str[sindex] = '\0';
  fprintf (fp, "%s\n", str);
  fflush (fp);

  free (str);
}

commit bash-20120224 snapshot


bind_tempenv_variable (name, value)
     const char *name;
     char *value;
{
  SHELL_VAR *var;

  var = temporary_env ? hash_lookup (name, temporary_env) : (SHELL_VAR *)NULL;

  if (var)
    {
      FREE (value_cell (var));
      var_setvalue (var, savestring (value));
      INVALIDATE_EXPORTSTR (var);
    }

  return (var);
}

commit bash-20120224 snapshot


find_variable_internal (name, force_tempenv)
     const char *name;
     int force_tempenv;
{
  SHELL_VAR *var;
  int search_tempenv;

  var = (SHELL_VAR *)NULL;

  /* If explicitly requested, first look in the temporary environment for
     the variable.  This allows constructs such as "foo=x eval 'echo $foo'"
     to get the `exported' value of $foo.  This happens if we are executing
     a function or builtin, or if we are looking up a variable in a
     "subshell environment". */
  search_tempenv = force_tempenv || (expanding_redir == 0 && subshell_environment);

  if (search_tempenv && temporary_env)
    var = hash_lookup (name, temporary_env);

  if (var == 0)
    var = var_lookup (name, shell_variables);

  if (var == 0)
    return ((SHELL_VAR *)NULL);

  return (var->dynamic_value ? (*(var->dynamic_value)) (var) : var);
}

commit bash-20120224 snapshot


sv_globignore (name)
     char *name;
{
  if (privileged_mode == 0)
    setup_glob_ignore (name);
}

commit bash-20120224 snapshot


cpl_prune ()
{
  struct cpelement *cp;

  while (coproc_list.head && coproc_list.ncoproc > COPROC_MAX)
    {
      cp = coproc_list.head;
      coproc_list.head = coproc_list.head->next;
      coproc_dispose (cp->coproc);
      cpe_dispose (cp);
      coproc_list.ncoproc--;
    }
}

commit bash-20120224 snapshot


kill_all_local_variables ()
{
  VAR_CONTEXT *vc;

  for (vc = shell_variables; vc; vc = vc->down)
    if (vc_isfuncenv (vc) && vc->scope == variable_context)
      break;
  if (vc == 0)
    return;		/* XXX */

  if (vc->table && vc_haslocals (vc))
    {
      delete_all_variables (vc->table);
      hash_dispose (vc->table);
    }
  vc->table = (HASH_TABLE *)NULL;
}

commit bash-20120224 snapshot


make_var_export_array (vcxt)
     VAR_CONTEXT *vcxt;
{
  char **list;
  SHELL_VAR **vars;

#if 0
  vars = map_over (visible_and_exported, vcxt);
#else
  vars = map_over (export_environment_candidate, vcxt);
#endif

  if (vars == 0)
    return (char **)NULL;

  list = make_env_array_from_var_list (vars);

  free (vars);
  return (list);
}

commit bash-20120224 snapshot


get_variable_value (var)
     SHELL_VAR *var;
{
  if (var == 0)
    return ((char *)NULL);
#if defined (ARRAY_VARS)
  else if (array_p (var))
    return (array_reference (array_cell (var), 0));
  else if (assoc_p (var))
    return (assoc_reference (assoc_cell (var), "0"));
#endif
  else
    return (value_cell (var));
}

commit bash-20120224 snapshot


qsort_var_comp (var1, var2)
     SHELL_VAR **var1, **var2;
{
  int result;

  if ((result = (*var1)->name[0] - (*var2)->name[0]) == 0)
    result = strcmp ((*var1)->name, (*var2)->name);

  return (result);
}

commit bash-20120224 snapshot


assign_in_env (word, flags)
     WORD_DESC *word;
     int flags;
{
  int offset;
  char *name, *temp, *value;
  SHELL_VAR *var;
  const char *string;

  string = word->word;

  offset = assignment (string, 0);
  name = savestring (string);
  value = (char *)NULL;

  if (name[offset] == '=')
    {
      name[offset] = 0;

      /* ignore the `+' when assigning temporary environment */
      if (name[offset - 1] == '+')
	name[offset - 1] = '\0';

      var = find_variable (name);
      if (var && (readonly_p (var) || noassign_p (var)))
	{
	  if (readonly_p (var))
	    err_readonly (name);
	  free (name);
  	  return (0);
	}

      temp = name + offset + 1;
      value = expand_assignment_string_to_string (temp, 0);
    }

  if (temporary_env == 0)
    temporary_env = hash_create (TEMPENV_HASH_BUCKETS);

  var = hash_lookup (name, temporary_env);
  if (var == 0)
    var = make_new_variable (name, temporary_env);
  else
    FREE (value_cell (var));

  if (value == 0)
    {
      value = (char *)xmalloc (1);	/* like do_assignment_internal */
      value[0] = '\0';
    }

  var_setvalue (var, value);
  var->attributes |= (att_exported|att_tempvar);
  var->context = variable_context;	/* XXX */

  INVALIDATE_EXPORTSTR (var);
  var->exportstr = mk_env_string (name, value);

  array_needs_making = 1;

#if 0
  if (ifsname (name))
    setifs (var);
else
#endif
  if (flags)
    stupidly_hack_special_variables (name);

  if (echo_command_at_execute)
    /* The Korn shell prints the `+ ' in front of assignment statements,
	so we do too. */
    xtrace_print_assignment (name, value, 0, 1);

  free (name);
  return 1;
}

commit bash-20120224 snapshot


all_visible_variables ()
{
  return (vapply (visible_var));
}

commit bash-20120224 snapshot


execute_command (command)
     COMMAND *command;
{
  struct fd_bitmap *bitmap;
  int result;

  current_fds_to_close = (struct fd_bitmap *)NULL;
  bitmap = new_fd_bitmap (FD_BITMAP_DEFAULT_SIZE);
  begin_unwind_frame ("execute-command");
  add_unwind_protect (dispose_fd_bitmap, (char *)bitmap);

  /* Just do the command, but not asynchronously. */
  result = execute_command_internal (command, 0, NO_PIPE, NO_PIPE, bitmap);

  dispose_fd_bitmap (bitmap);
  discard_unwind_frame ("execute-command");

#if defined (PROCESS_SUBSTITUTION)
  /* don't unlink fifos if we're in a shell function; wait until the function
     returns. */
  if (variable_context == 0)
    unlink_fifo_list ();
#endif /* PROCESS_SUBSTITUTION */

  QUIT;
  return (result);
}

commit bash-20120224 snapshot


coproc_closeall ()
{
#if MULTIPLE_COPROCS
  cpl_closeall ();
#else
  coproc_close (&sh_coproc);	/* XXX - will require changes for multiple coprocs */
#endif
}

commit bash-20120224 snapshot


coproc_fdchk (fd)
     int fd;
{
#if MULTIPLE_COPROCS
  cpl_fdchk (fd);
#else
  coproc_checkfd (&sh_coproc, fd);
#endif
}

commit bash-20120224 snapshot


ansiexpand (string, start, end, lenp)
     char *string;
     int start, end, *lenp;
{
  char *temp, *t;
  int len, tlen;

  temp = (char *)xmalloc (end - start + 1);
  for (tlen = 0, len = start; len < end; )
    temp[tlen++] = string[len++];
  temp[tlen] = '\0';

  if (*temp)
    {
      t = ansicstr (temp, tlen, 2, (int *)NULL, lenp);
      free (temp);
      return (t);
    }
  else
    {
      if (lenp)
	*lenp = 0;
      return (temp);
    }
}

commit bash-20120224 snapshot


bind_var_to_int (var, val)
     char *var;
     intmax_t val;
{
  char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p;

  p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0);
  return (bind_int_variable (var, p));
}

commit bash-20120224 snapshot


merge_temporary_env ()
{
  if (temporary_env)
    dispose_temporary_env (push_temp_var);
}

commit bash-20120224 snapshot


free_variable_hash_data (data)
     PTR_T data;
{
  SHELL_VAR *var;

  var = (SHELL_VAR *)data;
  dispose_variable (var);
}

commit bash-20120224 snapshot


getcoprocbypid (pid)
     pid_t pid;
{
#if MULTIPLE_COPROCS
  struct cpelement *p;

  p = cpl_search (pid);
  return (p ? p->coproc : 0);
#else
  return (pid == sh_coproc.c_pid ? &sh_coproc : 0);
#endif
}

commit bash-20120224 snapshot


coproc_fdrestore (cp)
     struct coproc *cp;
{
  cp->c_rfd = cp->c_rsave;
  cp->c_wfd = cp->c_wsave;
}

commit bash-20120224 snapshot


u32toutf16 (c, s)
     u_bits32_t c;
     unsigned short *s;
{
  int l;

  l = 0;
  if (c < 0x0d800)
    {
      s[0] = (unsigned short) (c & 0xFFFF);
      l = 1;
    }
  else if (c >= 0x0e000 && c <= 0x010ffff)
    {
      c -= 0x010000;
      s[0] = (unsigned short)((c >> 10) + 0xd800);
      s[1] = (unsigned short)((c & 0x3ff) + 0xdc00);
      l = 2;
    }
  s[l] = 0;
  return l;
}

commit bash-20120224 snapshot


err_readonly (s)
     const char *s;
{
  report_error (_("%s: readonly variable"), s);
}

commit bash-20120224 snapshot


find_special_var (name)
     const char *name;
{
  register int i, r;

  for (i = 0; special_vars[i].name; i++)
    {
      r = special_vars[i].name[0] - name[0];
      if (r == 0)
	r = strcmp (special_vars[i].name, name);
      if (r == 0)
	return i;
      else if (r > 0)
	/* Can't match any of rest of elements in sorted list.  Take this out
	   if it causes problems in certain environments. */
	break;
    }
  return -1;
}

commit bash-20120224 snapshot


execute_cond_node (cond)
     COND_COM *cond;
{
  int result, invert, patmatch, rmatch, mflags, ignore;
  char *arg1, *arg2;

  invert = (cond->flags & CMD_INVERT_RETURN);
  ignore = (cond->flags & CMD_IGNORE_RETURN);
  if (ignore)
    {
      if (cond->left)
	cond->left->flags |= CMD_IGNORE_RETURN;
      if (cond->right)
	cond->right->flags |= CMD_IGNORE_RETURN;
    }

  if (cond->type == COND_EXPR)
    result = execute_cond_node (cond->left);
  else if (cond->type == COND_OR)
    {
      result = execute_cond_node (cond->left);
      if (result != EXECUTION_SUCCESS)
	result = execute_cond_node (cond->right);
    }
  else if (cond->type == COND_AND)
    {
      result = execute_cond_node (cond->left);
      if (result == EXECUTION_SUCCESS)
	result = execute_cond_node (cond->right);
    }
  else if (cond->type == COND_UNARY)
    {
      if (ignore)
	comsub_ignore_return++;
      arg1 = cond_expand_word (cond->left->op, 0);
      if (ignore)
	comsub_ignore_return--;
      if (arg1 == 0)
	arg1 = nullstr;
      if (echo_command_at_execute)
	xtrace_print_cond_term (cond->type, invert, cond->op, arg1, (char *)NULL);
      result = unary_test (cond->op->word, arg1) ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
      if (arg1 != nullstr)
	free (arg1);
    }
  else if (cond->type == COND_BINARY)
    {
      rmatch = 0;
      patmatch = (((cond->op->word[1] == '=') && (cond->op->word[2] == '\0') &&
		   (cond->op->word[0] == '!' || cond->op->word[0] == '=')) ||
		  (cond->op->word[0] == '=' && cond->op->word[1] == '\0'));
#if defined (COND_REGEXP)
      rmatch = (cond->op->word[0] == '=' && cond->op->word[1] == '~' &&
		cond->op->word[2] == '\0');
#endif

      if (ignore)
	comsub_ignore_return++;
      arg1 = cond_expand_word (cond->left->op, 0);
      if (ignore)
	comsub_ignore_return--;
      if (arg1 == 0)
	arg1 = nullstr;
      if (ignore)
	comsub_ignore_return++;
      arg2 = cond_expand_word (cond->right->op,
			       (rmatch && shell_compatibility_level > 31) ? 2 : (patmatch ? 1 : 0));
      if (ignore)
	comsub_ignore_return--;
      if (arg2 == 0)
	arg2 = nullstr;

      if (echo_command_at_execute)
	xtrace_print_cond_term (cond->type, invert, cond->op, arg1, arg2);

#if defined (COND_REGEXP)
      if (rmatch)
	{
	  mflags = SHMAT_PWARN;
#if defined (ARRAY_VARS)
	  mflags |= SHMAT_SUBEXP;
#endif

	  result = sh_regmatch (arg1, arg2, mflags);
	}
      else
#endif /* COND_REGEXP */
	{
	  int oe;
	  oe = extended_glob;
	  extended_glob = 1;
	  result = binary_test (cond->op->word, arg1, arg2, TEST_PATMATCH|TEST_ARITHEXP|TEST_LOCALE)
				  ? EXECUTION_SUCCESS
				  : EXECUTION_FAILURE;
	  extended_glob = oe;
	}
      if (arg1 != nullstr)
	free (arg1);
      if (arg2 != nullstr)
	free (arg2);
    }
  else
    {
      command_error ("execute_cond_node", CMDERR_BADTYPE, cond->type, 0);
      jump_to_top_level (DISCARD);
      result = EXECUTION_FAILURE;
    }

  if (invert)
    result = (result == EXECUTION_SUCCESS) ? EXECUTION_FAILURE : EXECUTION_SUCCESS;

  return result;
}

commit bash-20120224 snapshot


set_ppid ()
{
  char namebuf[INT_STRLEN_BOUND(pid_t) + 1], *name;
  SHELL_VAR *temp_var;

  name = inttostr (getppid (), namebuf, sizeof(namebuf));
  temp_var = find_variable ("PPID");
  if (temp_var)
    VUNSETATTR (temp_var, (att_readonly | att_exported));
  temp_var = bind_variable ("PPID", name, 0);
  VSETATTR (temp_var, (att_readonly | att_integer));
}

commit bash-20120224 snapshot


error_prolog (print_lineno)
     int print_lineno;
{
  char *ename;
  int line;

  ename = get_name_for_error ();
  line = (print_lineno && interactive_shell == 0) ? executing_line_number () : -1;

  if (line > 0)
    fprintf (stderr, "%s:%s%d: ", ename, gnu_error_format ? "" : _(" line "), line);
  else
    fprintf (stderr, "%s: ", ename);
}

commit bash-20120224 snapshot


bind_int_variable (lhs, rhs)
     char *lhs, *rhs;
{
  register SHELL_VAR *v;
  int isint, isarr;

  isint = isarr = 0;
#if defined (ARRAY_VARS)
  if (valid_array_reference (lhs))
    {
      isarr = 1;
      v = array_variable_part (lhs, (char **)0, (int *)0);
    }
  else
#endif
    v = find_variable (lhs);

  if (v)
    {
      isint = integer_p (v);
      VUNSETATTR (v, att_integer);
    }

#if defined (ARRAY_VARS)
  if (isarr)
    v = assign_array_element (lhs, rhs, 0);
  else
#endif
    v = bind_variable (lhs, rhs, 0);

  if (v && isint)
    VSETATTR (v, att_integer);

  return (v);
}

commit bash-20120224 snapshot


lastpipe_cleanup (s)
     int s;
{
  unfreeze_jobs_list ();
}

commit bash-20120224 snapshot


vlist_add (vlist, var, flags)
     VARLIST *vlist;
     SHELL_VAR *var;
     int flags;
{
  register int i;

  for (i = 0; i < vlist->list_len; i++)
    if (STREQ (var->name, vlist->list[i]->name))
      break;
  if (i < vlist->list_len)
    return;

  if (i >= vlist->list_size)
    vlist = vlist_realloc (vlist, vlist->list_size + 16);

  vlist->list[vlist->list_len++] = var;
  vlist->list[vlist->list_len] = (SHELL_VAR *)NULL;
}

commit bash-20120224 snapshot


close_pipes (in, out)
     int in, out;
{
  if (in >= 0)
    close (in);
  if (out >= 0)
    close (out);
}

commit bash-20120224 snapshot


sv_locale (name)
     char *name;
{
  char *v;
  int r;

  v = get_string_value (name);
  if (name[0] == 'L' && name[1] == 'A')	/* LANG */
    r = set_lang (name, v);
  else
    r = set_locale_var (name, v);		/* LC_*, TEXTDOMAIN* */

#if 1
  if (r == 0 && posixly_correct)
    last_command_exit_value = 1;
#endif
}

commit bash-20120224 snapshot


execute_shell_script (sample, sample_len, command, args, env)
     char *sample;
     int sample_len;
     char *command;
     char **args, **env;
{
  char *execname, *firstarg;
  int i, start, size_increment, larry;

  /* Find the name of the interpreter to exec. */
  execname = getinterp (sample, sample_len, &i);
  size_increment = 1;

  /* Now the argument, if any. */
  for (firstarg = (char *)NULL, start = i; WHITECHAR(i); i++)
    ;

  /* If there is more text on the line, then it is an argument for the
     interpreter. */

  if (STRINGCHAR(i))
    {
      for (start = i; STRINGCHAR(i); i++)
	;
      firstarg = substring ((char *)sample, start, i);
      size_increment = 2;
    }

  larry = strvec_len (args) + size_increment;
  args = strvec_resize (args, larry + 1);

  for (i = larry - 1; i; i--)
    args[i] = args[i - size_increment];

  args[0] = execname;
  if (firstarg)
    {
      args[1] = firstarg;
      args[2] = command;
    }
  else
    args[1] = command;

  args[larry] = (char *)NULL;

  return (shell_execve (execname, args, env));
}

commit bash-20120224 snapshot


err_unboundvar (s)
     const char *s;
{
  report_error (_("%s: unbound variable"), s);
}

commit bash-20120224 snapshot


get_funcname (self)
     SHELL_VAR *self;
{
#if ! defined (ARRAY_VARS)
  char *t;
  if (variable_context && this_shell_function)
    {
      FREE (value_cell (self));
      t = savestring (this_shell_function->name);
      var_setvalue (self, t);
    }
#endif
  return (self);
}

commit bash-20120224 snapshot


get_word_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
/* This version is for reading raw-word-format PPM files with any maxval */
{
  ppm_source_ptr source = (ppm_source_ptr)sinfo;
  register JSAMPROW ptr;
  register U_CHAR *bufferptr;
  register JSAMPLE *rescale = source->rescale;
  JDIMENSION col;
  unsigned int maxval = source->maxval;
  register int rindex = rgb_red[cinfo->in_color_space];
  register int gindex = rgb_green[cinfo->in_color_space];
  register int bindex = rgb_blue[cinfo->in_color_space];
  register int aindex = alpha_index[cinfo->in_color_space];
  register int ps = rgb_pixelsize[cinfo->in_color_space];

  if (!ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
    ERREXIT(cinfo, JERR_INPUT_EOF);
  ptr = source->pub.buffer[0];
  bufferptr = source->iobuffer;
  for (col = cinfo->image_width; col > 0; col--) {
    register unsigned int temp;
    temp  = UCH(*bufferptr++) << 8;
    temp |= UCH(*bufferptr++);
    if (temp > maxval)
      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
    ptr[rindex] = rescale[temp];
    temp  = UCH(*bufferptr++) << 8;
    temp |= UCH(*bufferptr++);
    if (temp > maxval)
      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
    ptr[gindex] = rescale[temp];
    temp  = UCH(*bufferptr++) << 8;
    temp |= UCH(*bufferptr++);
    if (temp > maxval)
      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
    ptr[bindex] = rescale[temp];
    if (aindex >= 0)
      ptr[aindex] = 0xFF;
    ptr += ps;
  }
  return 1;
}

tjLoadImage: Fix issues w/loading 16-bit PPMs/PGMs

- The PPM reader now throws an error rather than segfaulting (due to a
  buffer overrun) if an application attempts to load a 16-bit PPM file
  into a grayscale uncompressed image buffer.  No known applications
  allowed that (not even the test applications in libjpeg-turbo),
  because that mode of operation was never expected to work and did not
  work under any circumstances.  (In fact, it was necessary to modify
  TJBench in order to reproduce the issue outside of a fuzzing
  environment.)  This was purely a matter of making the library bow out
  gracefully rather than crash if an application tries to do something
  really stupid.

- The PPM reader now throws an error rather than generating incorrect
  pixels if an application attempts to load a 16-bit PGM file into an
  RGB uncompressed image buffer.

- The PPM reader now correctly loads 16-bit PPM files into extended
  RGB uncompressed image buffers.  (Previously it generated incorrect
  pixels unless the input colorspace was JCS_RGB or JCS_EXT_RGB.)

The only way that users could have potentially encountered these issues
was through the tjLoadImage() function.  cjpeg and TJBench were
unaffected.


	return 0;
}

void iscsi_host_for_each_session(struct Scsi_Host *shost,
				 void (*fn)(struct iscsi_cls_session *))
{

scsi: iscsi: Verify lengths on passthrough PDUs

Open-iSCSI sends passthrough PDUs over netlink, but the kernel should be
verifying that the provided PDU header and data lengths fall within the
netlink message to prevent accessing beyond that in memory.

Cc: stable@vger.kernel.org
Reported-by: Adam Nichols <adam@grimm-co.com>
Reviewed-by: Lee Duncan <lduncan@suse.com>
Reviewed-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Chris Leech <cleech@redhat.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>


}
EXPORT_SYMBOL_GPL(iscsi_block_session);

static void __iscsi_unbind_session(struct work_struct *work)
{
	struct iscsi_cls_session *session =
			container_of(work, struct iscsi_cls_session,
				     unbind_work);
	struct Scsi_Host *shost = iscsi_session_to_shost(session);
	struct iscsi_cls_host *ihost = shost->shost_data;
	unsigned long flags;
	unsigned int target_id;

	ISCSI_DBG_TRANS_SESSION(session, "Unbinding session\n");

	/* Prevent new scans and make sure scanning is not in progress */
	mutex_lock(&ihost->mutex);
	spin_lock_irqsave(&session->lock, flags);
	if (session->target_id == ISCSI_MAX_TARGET) {
		spin_unlock_irqrestore(&session->lock, flags);
		mutex_unlock(&ihost->mutex);
		goto unbind_session_exit;
	}

	target_id = session->target_id;
	session->target_id = ISCSI_MAX_TARGET;
	spin_unlock_irqrestore(&session->lock, flags);
	mutex_unlock(&ihost->mutex);

	scsi_remove_target(&session->dev);

	if (session->ida_used)
		ida_simple_remove(&iscsi_sess_ida, target_id);

unbind_session_exit:


 * @session: iscsi class session
 * @event: type of event
 */
int iscsi_session_event(struct iscsi_cls_session *session,
			enum iscsi_uevent_e event)
{
	struct iscsi_internal *priv;
	struct Scsi_Host *shost;
	struct iscsi_uevent *ev;
	struct sk_buff  *skb;
	struct nlmsghdr *nlh;
	int rc, len = nlmsg_total_size(sizeof(*ev));

	priv = iscsi_if_transport_lookup(session->transport);
	if (!priv)
		return -EINVAL;
	shost = iscsi_session_to_shost(session);

	skb = alloc_skb(len, GFP_KERNEL);
	if (!skb) {
		iscsi_cls_session_printk(KERN_ERR, session,
					 "Cannot notify userspace of session "
					 "event %u\n", event);
		return -ENOMEM;
	}

	nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
	ev = nlmsg_data(nlh);
	ev->transport_handle = iscsi_handle(session->transport);

	ev->type = event;
	switch (event) {
	case ISCSI_KEVENT_DESTROY_SESSION:
		ev->r.d_session.host_no = shost->host_no;
		ev->r.d_session.sid = session->sid;
		break;
	case ISCSI_KEVENT_CREATE_SESSION:
		ev->r.c_session_ret.host_no = shost->host_no;
		ev->r.c_session_ret.sid = session->sid;
		break;
	case ISCSI_KEVENT_UNBIND_SESSION:
		ev->r.unbind_session.host_no = shost->host_no;
		ev->r.unbind_session.sid = session->sid;
		break;
	default:
		iscsi_cls_session_printk(KERN_ERR, session, "Invalid event "
					 "%u.\n", event);
		kfree_skb(skb);
		return -EINVAL;
	}

	/*
	 * this will occur if the daemon is not up, so we just warn
	 * the user and when the daemon is restarted it will handle it
	 */
	rc = iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_KERNEL);
	if (rc == -ESRCH)
		iscsi_cls_session_printk(KERN_ERR, session,
					 "Cannot notify userspace of session "
					 "event %u. Check iscsi daemon\n",
					 event);

	ISCSI_DBG_TRANS_SESSION(session, "Completed handling event %d rc %d\n",


}
EXPORT_SYMBOL_GPL(iscsi_unblock_session);

static void __iscsi_block_session(struct work_struct *work)
{
	struct iscsi_cls_session *session =
			container_of(work, struct iscsi_cls_session,
				     block_work);
	unsigned long flags;

	ISCSI_DBG_TRANS_SESSION(session, "Blocking session\n");
	spin_lock_irqsave(&session->lock, flags);
	session->state = ISCSI_SESSION_FAILED;
	spin_unlock_irqrestore(&session->lock, flags);
	scsi_target_block(&session->dev);
	ISCSI_DBG_TRANS_SESSION(session, "Completed SCSI target blocking\n");
	if (session->recovery_tmo >= 0)
		queue_delayed_work(iscsi_eh_timer_workq,


	NULL,
};

static void iscsi_flashnode_conn_release(struct device *dev)
{
	struct iscsi_bus_flash_conn *fnode_conn = iscsi_dev_to_flash_conn(dev);

	kfree(fnode_conn->ipaddress);
	kfree(fnode_conn->redirect_ipaddr);


static umode_t iscsi_iface_attr_is_visible(struct kobject *kobj,
					  struct attribute *attr, int i)
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct iscsi_iface *iface = iscsi_dev_to_iface(dev);
	struct iscsi_transport *t = iface->transport;
	int param;
	int param_type;

	if (attr == &dev_attr_iface_enabled.attr)
		param = ISCSI_NET_PARAM_IFACE_ENABLE;
	else if (attr == &dev_attr_iface_vlan_id.attr)
		param = ISCSI_NET_PARAM_VLAN_ID;
	else if (attr == &dev_attr_iface_vlan_priority.attr)
		param = ISCSI_NET_PARAM_VLAN_PRIORITY;
	else if (attr == &dev_attr_iface_vlan_enabled.attr)
		param = ISCSI_NET_PARAM_VLAN_ENABLED;
	else if (attr == &dev_attr_iface_mtu.attr)
		param = ISCSI_NET_PARAM_MTU;
	else if (attr == &dev_attr_iface_port.attr)
		param = ISCSI_NET_PARAM_PORT;
	else if (attr == &dev_attr_iface_ipaddress_state.attr)
		param = ISCSI_NET_PARAM_IPADDR_STATE;
	else if (attr == &dev_attr_iface_delayed_ack_en.attr)
		param = ISCSI_NET_PARAM_DELAYED_ACK_EN;
	else if (attr == &dev_attr_iface_tcp_nagle_disable.attr)
		param = ISCSI_NET_PARAM_TCP_NAGLE_DISABLE;
	else if (attr == &dev_attr_iface_tcp_wsf_disable.attr)
		param = ISCSI_NET_PARAM_TCP_WSF_DISABLE;
	else if (attr == &dev_attr_iface_tcp_wsf.attr)
		param = ISCSI_NET_PARAM_TCP_WSF;
	else if (attr == &dev_attr_iface_tcp_timer_scale.attr)
		param = ISCSI_NET_PARAM_TCP_TIMER_SCALE;
	else if (attr == &dev_attr_iface_tcp_timestamp_en.attr)
		param = ISCSI_NET_PARAM_TCP_TIMESTAMP_EN;
	else if (attr == &dev_attr_iface_cache_id.attr)
		param = ISCSI_NET_PARAM_CACHE_ID;
	else if (attr == &dev_attr_iface_redirect_en.attr)
		param = ISCSI_NET_PARAM_REDIRECT_EN;
	else if (attr == &dev_attr_iface_def_taskmgmt_tmo.attr)
		param = ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO;
	else if (attr == &dev_attr_iface_header_digest.attr)
		param = ISCSI_IFACE_PARAM_HDRDGST_EN;
	else if (attr == &dev_attr_iface_data_digest.attr)
		param = ISCSI_IFACE_PARAM_DATADGST_EN;
	else if (attr == &dev_attr_iface_immediate_data.attr)
		param = ISCSI_IFACE_PARAM_IMM_DATA_EN;
	else if (attr == &dev_attr_iface_initial_r2t.attr)
		param = ISCSI_IFACE_PARAM_INITIAL_R2T_EN;
	else if (attr == &dev_attr_iface_data_seq_in_order.attr)
		param = ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN;
	else if (attr == &dev_attr_iface_data_pdu_in_order.attr)
		param = ISCSI_IFACE_PARAM_PDU_INORDER_EN;
	else if (attr == &dev_attr_iface_erl.attr)
		param = ISCSI_IFACE_PARAM_ERL;
	else if (attr == &dev_attr_iface_max_recv_dlength.attr)
		param = ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH;
	else if (attr == &dev_attr_iface_first_burst_len.attr)
		param = ISCSI_IFACE_PARAM_FIRST_BURST;
	else if (attr == &dev_attr_iface_max_outstanding_r2t.attr)
		param = ISCSI_IFACE_PARAM_MAX_R2T;
	else if (attr == &dev_attr_iface_max_burst_len.attr)
		param = ISCSI_IFACE_PARAM_MAX_BURST;
	else if (attr == &dev_attr_iface_chap_auth.attr)
		param = ISCSI_IFACE_PARAM_CHAP_AUTH_EN;
	else if (attr == &dev_attr_iface_bidi_chap.attr)
		param = ISCSI_IFACE_PARAM_BIDI_CHAP_EN;
	else if (attr == &dev_attr_iface_discovery_auth_optional.attr)
		param = ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL;
	else if (attr == &dev_attr_iface_discovery_logout.attr)
		param = ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN;
	else if (attr == &dev_attr_iface_strict_login_comp_en.attr)
		param = ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN;
	else if (attr == &dev_attr_iface_initiator_name.attr)
		param = ISCSI_IFACE_PARAM_INITIATOR_NAME;
	else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) {
		if (attr == &dev_attr_ipv4_iface_ipaddress.attr)
			param = ISCSI_NET_PARAM_IPV4_ADDR;
		else if (attr == &dev_attr_ipv4_iface_gateway.attr)
			param = ISCSI_NET_PARAM_IPV4_GW;
		else if (attr == &dev_attr_ipv4_iface_subnet.attr)
			param = ISCSI_NET_PARAM_IPV4_SUBNET;
		else if (attr == &dev_attr_ipv4_iface_bootproto.attr)
			param = ISCSI_NET_PARAM_IPV4_BOOTPROTO;
		else if (attr ==
			 &dev_attr_ipv4_iface_dhcp_dns_address_en.attr)
			param = ISCSI_NET_PARAM_IPV4_DHCP_DNS_ADDR_EN;
		else if (attr ==
			 &dev_attr_ipv4_iface_dhcp_slp_da_info_en.attr)
			param = ISCSI_NET_PARAM_IPV4_DHCP_SLP_DA_EN;
		else if (attr == &dev_attr_ipv4_iface_tos_en.attr)
			param = ISCSI_NET_PARAM_IPV4_TOS_EN;
		else if (attr == &dev_attr_ipv4_iface_tos.attr)
			param = ISCSI_NET_PARAM_IPV4_TOS;
		else if (attr == &dev_attr_ipv4_iface_grat_arp_en.attr)
			param = ISCSI_NET_PARAM_IPV4_GRAT_ARP_EN;
		else if (attr ==
			 &dev_attr_ipv4_iface_dhcp_alt_client_id_en.attr)
			param = ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID_EN;
		else if (attr == &dev_attr_ipv4_iface_dhcp_alt_client_id.attr)
			param = ISCSI_NET_PARAM_IPV4_DHCP_ALT_CLIENT_ID;
		else if (attr ==
			 &dev_attr_ipv4_iface_dhcp_req_vendor_id_en.attr)
			param = ISCSI_NET_PARAM_IPV4_DHCP_REQ_VENDOR_ID_EN;
		else if (attr ==
			 &dev_attr_ipv4_iface_dhcp_use_vendor_id_en.attr)
			param = ISCSI_NET_PARAM_IPV4_DHCP_USE_VENDOR_ID_EN;
		else if (attr == &dev_attr_ipv4_iface_dhcp_vendor_id.attr)
			param = ISCSI_NET_PARAM_IPV4_DHCP_VENDOR_ID;
		else if (attr ==
			 &dev_attr_ipv4_iface_dhcp_learn_iqn_en.attr)
			param = ISCSI_NET_PARAM_IPV4_DHCP_LEARN_IQN_EN;
		else if (attr ==
			 &dev_attr_ipv4_iface_fragment_disable.attr)
			param = ISCSI_NET_PARAM_IPV4_FRAGMENT_DISABLE;
		else if (attr ==
			 &dev_attr_ipv4_iface_incoming_forwarding_en.attr)
			param = ISCSI_NET_PARAM_IPV4_IN_FORWARD_EN;
		else if (attr == &dev_attr_ipv4_iface_ttl.attr)
			param = ISCSI_NET_PARAM_IPV4_TTL;
		else
			return 0;
	} else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) {
		if (attr == &dev_attr_ipv6_iface_ipaddress.attr)
			param = ISCSI_NET_PARAM_IPV6_ADDR;
		else if (attr == &dev_attr_ipv6_iface_link_local_addr.attr)
			param = ISCSI_NET_PARAM_IPV6_LINKLOCAL;
		else if (attr == &dev_attr_ipv6_iface_router_addr.attr)
			param = ISCSI_NET_PARAM_IPV6_ROUTER;
		else if (attr == &dev_attr_ipv6_iface_ipaddr_autocfg.attr)
			param = ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG;
		else if (attr == &dev_attr_ipv6_iface_link_local_autocfg.attr)
			param = ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG;
		else if (attr == &dev_attr_ipv6_iface_link_local_state.attr)
			param = ISCSI_NET_PARAM_IPV6_LINKLOCAL_STATE;
		else if (attr == &dev_attr_ipv6_iface_router_state.attr)
			param = ISCSI_NET_PARAM_IPV6_ROUTER_STATE;
		else if (attr ==
			 &dev_attr_ipv6_iface_grat_neighbor_adv_en.attr)
			param = ISCSI_NET_PARAM_IPV6_GRAT_NEIGHBOR_ADV_EN;
		else if (attr == &dev_attr_ipv6_iface_mld_en.attr)
			param = ISCSI_NET_PARAM_IPV6_MLD_EN;
		else if (attr == &dev_attr_ipv6_iface_flow_label.attr)
			param = ISCSI_NET_PARAM_IPV6_FLOW_LABEL;
		else if (attr == &dev_attr_ipv6_iface_traffic_class.attr)
			param = ISCSI_NET_PARAM_IPV6_TRAFFIC_CLASS;
		else if (attr == &dev_attr_ipv6_iface_hop_limit.attr)
			param = ISCSI_NET_PARAM_IPV6_HOP_LIMIT;
		else if (attr == &dev_attr_ipv6_iface_nd_reachable_tmo.attr)
			param = ISCSI_NET_PARAM_IPV6_ND_REACHABLE_TMO;
		else if (attr == &dev_attr_ipv6_iface_nd_rexmit_time.attr)
			param = ISCSI_NET_PARAM_IPV6_ND_REXMIT_TIME;
		else if (attr == &dev_attr_ipv6_iface_nd_stale_tmo.attr)
			param = ISCSI_NET_PARAM_IPV6_ND_STALE_TMO;
		else if (attr == &dev_attr_ipv6_iface_dup_addr_detect_cnt.attr)
			param = ISCSI_NET_PARAM_IPV6_DUP_ADDR_DETECT_CNT;
		else if (attr == &dev_attr_ipv6_iface_router_adv_link_mtu.attr)
			param = ISCSI_NET_PARAM_IPV6_RTR_ADV_LINK_MTU;
		else
			return 0;
	} else {
		WARN_ONCE(1, "Invalid iface attr");
		return 0;
	}

	switch (param) {
	case ISCSI_IFACE_PARAM_DEF_TASKMGMT_TMO:
	case ISCSI_IFACE_PARAM_HDRDGST_EN:
	case ISCSI_IFACE_PARAM_DATADGST_EN:
	case ISCSI_IFACE_PARAM_IMM_DATA_EN:
	case ISCSI_IFACE_PARAM_INITIAL_R2T_EN:
	case ISCSI_IFACE_PARAM_DATASEQ_INORDER_EN:
	case ISCSI_IFACE_PARAM_PDU_INORDER_EN:
	case ISCSI_IFACE_PARAM_ERL:
	case ISCSI_IFACE_PARAM_MAX_RECV_DLENGTH:
	case ISCSI_IFACE_PARAM_FIRST_BURST:
	case ISCSI_IFACE_PARAM_MAX_R2T:
	case ISCSI_IFACE_PARAM_MAX_BURST:
	case ISCSI_IFACE_PARAM_CHAP_AUTH_EN:
	case ISCSI_IFACE_PARAM_BIDI_CHAP_EN:
	case ISCSI_IFACE_PARAM_DISCOVERY_AUTH_OPTIONAL:
	case ISCSI_IFACE_PARAM_DISCOVERY_LOGOUT_EN:
	case ISCSI_IFACE_PARAM_STRICT_LOGIN_COMP_EN:
	case ISCSI_IFACE_PARAM_INITIATOR_NAME:
		param_type = ISCSI_IFACE_PARAM;
		break;
	default:
		param_type = ISCSI_NET_PARAM;
	}

	return t->attr_is_visible(param_type, param);


	NULL,
};

static umode_t iscsi_flashnode_conn_attr_is_visible(struct kobject *kobj,
						    struct attribute *attr,
						    int i)
{
	struct device *dev = container_of(kobj, struct device, kobj);
	struct iscsi_bus_flash_conn *fnode_conn = iscsi_dev_to_flash_conn(dev);
	struct iscsi_transport *t = fnode_conn->transport;
	int param;

	if (attr == &dev_attr_fnode_is_fw_assigned_ipv6.attr) {
		param = ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6;
	} else if (attr == &dev_attr_fnode_header_digest.attr) {
		param = ISCSI_FLASHNODE_HDR_DGST_EN;
	} else if (attr == &dev_attr_fnode_data_digest.attr) {
		param = ISCSI_FLASHNODE_DATA_DGST_EN;
	} else if (attr == &dev_attr_fnode_snack_req.attr) {
		param = ISCSI_FLASHNODE_SNACK_REQ_EN;
	} else if (attr == &dev_attr_fnode_tcp_timestamp_stat.attr) {
		param = ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT;
	} else if (attr == &dev_attr_fnode_tcp_nagle_disable.attr) {
		param = ISCSI_FLASHNODE_TCP_NAGLE_DISABLE;
	} else if (attr == &dev_attr_fnode_tcp_wsf_disable.attr) {
		param = ISCSI_FLASHNODE_TCP_WSF_DISABLE;
	} else if (attr == &dev_attr_fnode_tcp_timer_scale.attr) {
		param = ISCSI_FLASHNODE_TCP_TIMER_SCALE;
	} else if (attr == &dev_attr_fnode_tcp_timestamp_enable.attr) {
		param = ISCSI_FLASHNODE_TCP_TIMESTAMP_EN;
	} else if (attr == &dev_attr_fnode_fragment_disable.attr) {
		param = ISCSI_FLASHNODE_IP_FRAG_DISABLE;
	} else if (attr == &dev_attr_fnode_max_recv_dlength.attr) {
		param = ISCSI_FLASHNODE_MAX_RECV_DLENGTH;
	} else if (attr == &dev_attr_fnode_max_xmit_dlength.attr) {
		param = ISCSI_FLASHNODE_MAX_XMIT_DLENGTH;
	} else if (attr == &dev_attr_fnode_keepalive_tmo.attr) {
		param = ISCSI_FLASHNODE_KEEPALIVE_TMO;
	} else if (attr == &dev_attr_fnode_port.attr) {
		param = ISCSI_FLASHNODE_PORT;
	} else if (attr == &dev_attr_fnode_ipaddress.attr) {
		param = ISCSI_FLASHNODE_IPADDR;
	} else if (attr == &dev_attr_fnode_redirect_ipaddr.attr) {
		param = ISCSI_FLASHNODE_REDIRECT_IPADDR;
	} else if (attr == &dev_attr_fnode_max_segment_size.attr) {
		param = ISCSI_FLASHNODE_MAX_SEGMENT_SIZE;
	} else if (attr == &dev_attr_fnode_local_port.attr) {
		param = ISCSI_FLASHNODE_LOCAL_PORT;
	} else if (attr == &dev_attr_fnode_ipv4_tos.attr) {
		param = ISCSI_FLASHNODE_IPV4_TOS;
	} else if (attr == &dev_attr_fnode_ipv6_traffic_class.attr) {
		param = ISCSI_FLASHNODE_IPV6_TC;
	} else if (attr == &dev_attr_fnode_ipv6_flow_label.attr) {
		param = ISCSI_FLASHNODE_IPV6_FLOW_LABEL;
	} else if (attr == &dev_attr_fnode_link_local_ipv6.attr) {
		param = ISCSI_FLASHNODE_LINK_LOCAL_IPV6;
	} else if (attr == &dev_attr_fnode_tcp_xmit_wsf.attr) {
		param = ISCSI_FLASHNODE_TCP_XMIT_WSF;
	} else if (attr == &dev_attr_fnode_tcp_recv_wsf.attr) {
		param = ISCSI_FLASHNODE_TCP_RECV_WSF;
	} else if (attr == &dev_attr_fnode_statsn.attr) {
		param = ISCSI_FLASHNODE_STATSN;
	} else if (attr == &dev_attr_fnode_exp_statsn.attr) {
		param = ISCSI_FLASHNODE_EXP_STATSN;
	} else {
		WARN_ONCE(1, "Invalid flashnode connection attr");
		return 0;
	}


EXPORT_SYMBOL_GPL(iscsi_ping_comp_event);

static int
iscsi_if_send_reply(u32 portid, int type, void *payload, int size)
{
	struct sk_buff	*skb;
	struct nlmsghdr	*nlh;
	int len = nlmsg_total_size(size);

	skb = alloc_skb(len, GFP_ATOMIC);
	if (!skb) {
		printk(KERN_ERR "Could not allocate skb to send reply.\n");
		return -ENOMEM;
	}

	nlh = __nlmsg_put(skb, 0, 0, type, (len - sizeof(*nlh)), 0);


	return dev->release == iscsi_conn_release;
}

static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data)
{
	if (!iscsi_is_conn_dev(dev))


 * recovery timer fires then FAST_IO_FAIL is returned. The caller
 * should pass this error value to the scsi eh.
 */
int iscsi_block_scsi_eh(struct scsi_cmnd *cmd)
{
	struct iscsi_cls_session *session =
			starget_to_session(scsi_target(cmd->device));
	unsigned long flags;
	int ret = 0;

	spin_lock_irqsave(&session->lock, flags);
	while (session->state != ISCSI_SESSION_LOGGED_IN) {
		if (session->state == ISCSI_SESSION_FREE) {
			ret = FAST_IO_FAIL;
			break;
		}
		spin_unlock_irqrestore(&session->lock, flags);
		msleep(1000);
		spin_lock_irqsave(&session->lock, flags);
	}


	return err;
}

static int iscsi_logout_flashnode(struct iscsi_transport *transport,
				  struct iscsi_uevent *ev)
{
	struct Scsi_Host *shost;
	struct iscsi_bus_flash_session *fnode_sess;
	struct iscsi_bus_flash_conn *fnode_conn;
	struct device *dev;
	uint32_t idx;
	int err = 0;

	if (!transport->logout_flashnode) {
		err = -ENOSYS;
		goto exit_logout_fnode;
	}

	shost = scsi_host_lookup(ev->u.logout_flashnode.host_no);
	if (!shost) {
		pr_err("%s could not find host no %u\n",
		       __func__, ev->u.logout_flashnode.host_no);
		err = -ENODEV;
		goto put_host;
	}

	idx = ev->u.logout_flashnode.flashnode_idx;
	fnode_sess = iscsi_get_flashnode_by_index(shost, idx);
	if (!fnode_sess) {
		pr_err("%s could not find flashnode %u for host no %u\n",
		       __func__, idx, ev->u.logout_flashnode.host_no);
		err = -ENODEV;
		goto put_host;
	}

	dev = iscsi_find_flashnode_conn(fnode_sess);
	if (!dev) {
		err = -ENODEV;
		goto put_sess;
	}

	fnode_conn = iscsi_dev_to_flash_conn(dev);

	err = transport->logout_flashnode(fnode_sess, fnode_conn);
	put_device(dev);

put_sess:
	put_device(&fnode_sess->dev);

put_host:
	scsi_host_put(shost);


 * non-zero.
 */
struct iscsi_cls_conn *
iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
{
	struct iscsi_transport *transport = session->transport;
	struct iscsi_cls_conn *conn;
	unsigned long flags;
	int err;

	conn = kzalloc(sizeof(*conn) + dd_size, GFP_KERNEL);
	if (!conn)
		return NULL;
	if (dd_size)
		conn->dd_data = &conn[1];

	mutex_init(&conn->ep_mutex);
	INIT_LIST_HEAD(&conn->conn_list);
	INIT_LIST_HEAD(&conn->conn_list_err);
	conn->transport = transport;
	conn->cid = cid;
	conn->state = ISCSI_CONN_DOWN;

	/* this is released in the dev's release function */
	if (!get_device(&session->dev))
		goto free_conn;

	dev_set_name(&conn->dev, "connection%d:%u", session->sid, cid);
	conn->dev.parent = &session->dev;
	conn->dev.release = iscsi_conn_release;
	err = device_register(&conn->dev);
	if (err) {
		iscsi_cls_session_printk(KERN_ERR, session, "could not "
					 "register connection's dev\n");
		goto release_parent_ref;
	}
	err = transport_register_device(&conn->dev);
	if (err) {
		iscsi_cls_session_printk(KERN_ERR, session, "could not "
					 "register transport's dev\n");
		goto release_conn_ref;
	}

	spin_lock_irqsave(&connlock, flags);
	list_add(&conn->conn_list, &connlist);
	spin_unlock_irqrestore(&connlock, flags);

	ISCSI_DBG_TRANS_CONN(conn, "Completed conn creation\n");
	return conn;

release_conn_ref:
	device_unregister(&conn->dev);
	put_device(&session->dev);
	return NULL;
release_parent_ref:
	put_device(&session->dev);
free_conn:


}
EXPORT_SYMBOL_GPL(iscsi_unregister_transport);

void iscsi_dbg_trace(void (*trace)(struct device *dev, struct va_format *),
		     struct device *dev, const char *fmt, ...)
{
	struct va_format vaf;
	va_list args;

	va_start(args, fmt);
	vaf.fmt = fmt;
	vaf.va = &args;


	return dev->bus == &iscsi_flashnode_bus;
}

static int iscsi_destroy_flashnode_conn(struct iscsi_bus_flash_conn *fnode_conn)
{


}
EXPORT_SYMBOL_GPL(iscsi_get_discovery_parent_name);

static int iscsi_set_flashnode_param(struct iscsi_transport *transport,
				     struct iscsi_uevent *ev, uint32_t len)
{
	char *data = (char *)ev + sizeof(*ev);
	struct Scsi_Host *shost;
	struct iscsi_bus_flash_session *fnode_sess;
	struct iscsi_bus_flash_conn *fnode_conn;
	struct device *dev;
	uint32_t idx;
	int err = 0;

	if (!transport->set_flashnode_param) {
		err = -ENOSYS;
		goto exit_set_fnode;
	}

	shost = scsi_host_lookup(ev->u.set_flashnode.host_no);
	if (!shost) {
		pr_err("%s could not find host no %u\n",
		       __func__, ev->u.set_flashnode.host_no);
		err = -ENODEV;
		goto exit_set_fnode;
	}

	idx = ev->u.set_flashnode.flashnode_idx;
	fnode_sess = iscsi_get_flashnode_by_index(shost, idx);
	if (!fnode_sess) {
		pr_err("%s could not find flashnode %u for host no %u\n",
		       __func__, idx, ev->u.set_flashnode.host_no);
		err = -ENODEV;
		goto put_host;
	}

	dev = iscsi_find_flashnode_conn(fnode_sess);
	if (!dev) {
		err = -ENODEV;
		goto put_sess;
	}

	fnode_conn = iscsi_dev_to_flash_conn(dev);
	err = transport->set_flashnode_param(fnode_sess, fnode_conn, data, len);
	put_device(dev);

put_sess:
	put_device(&fnode_sess->dev);

put_host:
	scsi_host_put(shost);


	return err;
}

static int iscsi_session_has_conns(int sid)
{
	struct iscsi_cls_conn *conn;
	unsigned long flags;
	int found = 0;

	spin_lock_irqsave(&connlock, flags);
	list_for_each_entry(conn, &connlist, conn_list) {
		if (iscsi_conn_get_sid(conn) == sid) {
			found = 1;
			break;
		}
	}
	spin_unlock_irqrestore(&connlock, flags);


}

static int
iscsi_tgt_dscvr(struct iscsi_transport *transport,
		struct iscsi_uevent *ev)
{
	struct Scsi_Host *shost;
	struct sockaddr *dst_addr;
	int err;

	if (!transport->tgt_dscvr)
		return -EINVAL;

	shost = scsi_host_lookup(ev->u.tgt_dscvr.host_no);
	if (!shost) {
		printk(KERN_ERR "target discovery could not find host no %u\n",
		       ev->u.tgt_dscvr.host_no);
		return -ENODEV;
	}

	dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
	err = transport->tgt_dscvr(shost, ev->u.tgt_dscvr.type,
				   ev->u.tgt_dscvr.enable, dst_addr);


char *iscsi_get_router_state_name(enum iscsi_router_state router_state)
{
	int i;
	char *state = NULL;

	for (i = 0; i < ARRAY_SIZE(iscsi_router_state_names); i++) {
		if (iscsi_router_state_names[i].value == router_state) {
			state = iscsi_router_state_names[i].name;
			break;
		}
	}
	return state;


struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
{
	struct iscsi_endpoint *ep;
	struct device *dev;

	dev = class_find_device(&iscsi_endpoint_class, NULL, &handle,
				iscsi_match_epid);
	if (!dev)
		return NULL;

	ep = iscsi_dev_to_endpoint(dev);
	/*
	 * we can drop this now because the interface will prevent
	 * removals and lookups from racing.
	 */
	put_device(dev);
	return ep;
}


 * Destroys all the flashnode session entries and all corresponding children
 * flashnode connection entries from sysfs
 */
void iscsi_destroy_all_flashnode(struct Scsi_Host *shost)
{


}
EXPORT_SYMBOL_GPL(iscsi_session_chkready);

int iscsi_is_session_online(struct iscsi_cls_session *session)
{
	unsigned long flags;
	int ret = 0;

	spin_lock_irqsave(&session->lock, flags);
	if (session->state == ISCSI_SESSION_LOGGED_IN)
		ret = 1;


iscsi_session_attr(discovery_parent_type, ISCSI_PARAM_DISCOVERY_PARENT_TYPE, 0);

static ssize_t
show_priv_session_state(struct device *dev, struct device_attribute *attr,
			char *buf)
{


 * @ihost: iscsi_cls_host adding the structures to
 */
static int
iscsi_bsg_host_add(struct Scsi_Host *shost, struct iscsi_cls_host *ihost)
{
	struct device *dev = &shost->shost_gendev;
	struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
	struct request_queue *q;
	char bsg_name[20];

	if (!i->iscsi_transport->bsg_request)
		return -ENOTSUPP;

	snprintf(bsg_name, sizeof(bsg_name), "iscsi_host%d", shost->host_no);
	q = bsg_setup_queue(dev, bsg_name, iscsi_bsg_host_dispatch, NULL, 0);
	if (IS_ERR(q)) {
		shost_printk(KERN_ERR, shost, "bsg interface failed to "
			     "initialize - no request queue\n");
		return PTR_ERR(q);
	}
	__scsi_init_queue(shost, q);


static int iscsi_match_epid(struct device *dev, const void *data)
{
	struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
	const uint64_t *epid = data;

	return *epid == ep->id;
}


	return 0;
}

static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
			   uint id, u64 lun)
{
	struct iscsi_scan_data scan_data;

	scan_data.channel = channel;
	scan_data.id = id;
	scan_data.lun = lun;
	scan_data.rescan = SCSI_SCAN_MANUAL;


}
EXPORT_SYMBOL_GPL(iscsi_find_flashnode_conn);

static int iscsi_iter_destroy_flashnode_conn_fn(struct device *dev, void *data)
{
	if (!iscsi_is_flashnode_conn_dev(dev, NULL))
		return 0;


}

static int
iscsi_send_ping(struct iscsi_transport *transport, struct iscsi_uevent *ev)
{
	struct Scsi_Host *shost;
	struct sockaddr *dst_addr;
	int err;

	if (!transport->send_ping)
		return -ENOSYS;

	shost = scsi_host_lookup(ev->u.iscsi_ping.host_no);
	if (!shost) {
		printk(KERN_ERR "iscsi_ping could not find host no %u\n",
		       ev->u.iscsi_ping.host_no);
		return -ENODEV;
	}

	dst_addr = (struct sockaddr *)((char *)ev + sizeof(*ev));
	err = transport->send_ping(shost, ev->u.iscsi_ping.iface_num,
				   ev->u.iscsi_ping.iface_type,
				   ev->u.iscsi_ping.payload_size,
				   ev->u.iscsi_ping.pid,
				   dst_addr);


	return nlmsg_unicast(nls, skb, portid);
}

int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
		   char *data, uint32_t data_size)
{
	struct nlmsghdr	*nlh;
	struct sk_buff *skb;
	struct iscsi_uevent *ev;
	char *pdu;
	struct iscsi_internal *priv;
	int len = nlmsg_total_size(sizeof(*ev) + sizeof(struct iscsi_hdr) +
				   data_size);

	priv = iscsi_if_transport_lookup(conn->transport);
	if (!priv)
		return -EINVAL;

	skb = alloc_skb(len, GFP_ATOMIC);
	if (!skb) {
		iscsi_conn_error_event(conn, ISCSI_ERR_CONN_FAILED);
		iscsi_cls_conn_printk(KERN_ERR, conn, "can not deliver "
				      "control PDU: OOM\n");
		return -ENOMEM;
	}

	nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
	ev = nlmsg_data(nlh);
	memset(ev, 0, sizeof(*ev));
	ev->transport_handle = iscsi_handle(conn->transport);
	ev->type = ISCSI_KEVENT_RECV_PDU;
	ev->r.recv_req.cid = conn->cid;
	ev->r.recv_req.sid = iscsi_conn_get_sid(conn);
	pdu = (char*)ev + sizeof(*ev);
	memcpy(pdu, hdr, sizeof(struct iscsi_hdr));
	memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size);


	{ISCSI_DISC_PARENT_ISNS,	"isns" },
};

char *iscsi_get_discovery_parent_name(int parent_type)
{
	int i;
	char *state = "Unknown!";

	for (i = 0; i < ARRAY_SIZE(iscsi_discovery_parent_names); i++) {
		if (iscsi_discovery_parent_names[i].value & parent_type) {
			state = iscsi_discovery_parent_names[i].name;
			break;
		}


	return err;
}

static int iscsi_del_flashnode(struct iscsi_transport *transport,
			       struct iscsi_uevent *ev)
{
	struct Scsi_Host *shost;
	struct iscsi_bus_flash_session *fnode_sess;
	uint32_t idx;
	int err = 0;

	if (!transport->del_flashnode) {
		err = -ENOSYS;
		goto exit_del_fnode;
	}

	shost = scsi_host_lookup(ev->u.del_flashnode.host_no);
	if (!shost) {
		pr_err("%s could not find host no %u\n",
		       __func__, ev->u.del_flashnode.host_no);
		err = -ENODEV;
		goto put_host;
	}

	idx = ev->u.del_flashnode.flashnode_idx;
	fnode_sess = iscsi_get_flashnode_by_index(shost, idx);
	if (!fnode_sess) {
		pr_err("%s could not find flashnode %u for host no %u\n",
		       __func__, idx, ev->u.del_flashnode.host_no);
		err = -ENODEV;
		goto put_host;
	}

	err = transport->del_flashnode(fnode_sess);
	put_device(&fnode_sess->dev);

put_host:
	scsi_host_put(shost);


	}
}

void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
{
	struct nlmsghdr	*nlh;
	struct sk_buff	*skb;
	struct iscsi_uevent *ev;
	struct iscsi_internal *priv;
	int len = nlmsg_total_size(sizeof(*ev));
	unsigned long flags;

	spin_lock_irqsave(&connlock, flags);
	list_add(&conn->conn_list_err, &connlist_err);
	spin_unlock_irqrestore(&connlock, flags);
	queue_work(system_unbound_wq, &stop_conn_work);

	priv = iscsi_if_transport_lookup(conn->transport);
	if (!priv)
		return;

	skb = alloc_skb(len, GFP_ATOMIC);
	if (!skb) {
		iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored "
				      "conn error (%d)\n", error);
		return;
	}

	nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
	ev = nlmsg_data(nlh);
	ev->transport_handle = iscsi_handle(conn->transport);
	ev->type = ISCSI_KEVENT_CONN_ERROR;
	ev->r.connerror.error = error;
	ev->r.connerror.cid = conn->cid;
	ev->r.connerror.sid = iscsi_conn_get_sid(conn);

	iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);


}

static int
iscsi_set_iface_params(struct iscsi_transport *transport,
		       struct iscsi_uevent *ev, uint32_t len)
{
	char *data = (char *)ev + sizeof(*ev);
	struct Scsi_Host *shost;
	int err;

	if (!transport->set_iface_param)
		return -ENOSYS;

	shost = scsi_host_lookup(ev->u.set_iface_params.host_no);
	if (!shost) {
		printk(KERN_ERR "set_iface_params could not find host no %u\n",
		       ev->u.set_iface_params.host_no);
		return -ENODEV;
	}

	err = transport->set_iface_param(shost, data, len);


	return &priv->conn_cont.ac == cont;
}

static int iscsi_host_match(struct attribute_container *cont,
			    struct device *dev)
{
	struct Scsi_Host *shost;
	struct iscsi_internal *priv;

	if (!scsi_is_host_device(dev))
		return 0;

	shost = dev_to_shost(dev);
	if (!shost->transportt  ||
	    shost->transportt->host_attrs.ac.class != &iscsi_host_class.class)
		return 0;


static ISCSI_CLASS_ATTR(priv_sess, creator, S_IRUGO, show_priv_session_creator,
			NULL);
static ssize_t
show_priv_session_target_id(struct device *dev, struct device_attribute *attr,
			    char *buf)
{


}

static int
iscsi_if_transport_ep(struct iscsi_transport *transport,
		      struct iscsi_uevent *ev, int msg_type)
{
	struct iscsi_endpoint *ep;
	int rc = 0;

	switch (msg_type) {
	case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
	case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
		rc = iscsi_if_ep_connect(transport, ev, msg_type);
		break;
	case ISCSI_UEVENT_TRANSPORT_EP_POLL:
		if (!transport->ep_poll)
			return -EINVAL;

		ep = iscsi_lookup_endpoint(ev->u.ep_poll.ep_handle);
		if (!ep)
			return -EINVAL;

		ev->r.retcode = transport->ep_poll(ep,
						   ev->u.ep_poll.timeout_ms);
		break;
	case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
		rc = iscsi_if_ep_disconnect(transport,
					    ev->u.ep_disconnect.ep_handle);
		break;


}

struct iscsi_cls_session *
iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
		    int dd_size)
{
	struct iscsi_cls_session *session;

	session = kzalloc(sizeof(*session) + dd_size,
			  GFP_KERNEL);
	if (!session)
		return NULL;

	session->transport = transport;
	session->creator = -1;
	session->recovery_tmo = 120;
	session->recovery_tmo_sysfs_override = false;
	session->state = ISCSI_SESSION_FREE;
	INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
	INIT_LIST_HEAD(&session->sess_list);
	INIT_WORK(&session->unblock_work, __iscsi_unblock_session);
	INIT_WORK(&session->block_work, __iscsi_block_session);
	INIT_WORK(&session->unbind_work, __iscsi_unbind_session);
	INIT_WORK(&session->scan_work, iscsi_scan_session);
	INIT_WORK(&session->destroy_work, __iscsi_destroy_session);
	spin_lock_init(&session->lock);

	/* this is released in the dev's release function */
	scsi_host_get(shost);
	session->dev.parent = &shost->shost_gendev;
	session->dev.release = iscsi_session_release;
	device_initialize(&session->dev);
	if (dd_size)
		session->dd_data = &session[1];


static void iscsi_transport_release(struct device *dev)
{
	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
	kfree(priv);
}


	return err;
}

static int iscsi_delete_chap(struct iscsi_transport *transport,
			     struct iscsi_uevent *ev)
{
	struct Scsi_Host *shost;
	int err = 0;

	if (!transport->delete_chap)
		return -ENOSYS;

	shost = scsi_host_lookup(ev->u.delete_chap.host_no);
	if (!shost) {
		printk(KERN_ERR "%s could not find host no %u\n",
		       __func__, ev->u.delete_chap.host_no);
		return -ENODEV;
	}

	err = transport->delete_chap(shost, ev->u.delete_chap.chap_tbl_idx);


	{ ISCSI_SESSION_FREE,		"FREE" },
};

static const char *iscsi_session_state_name(int state)
{
	int i;
	char *name = NULL;

	for (i = 0; i < ARRAY_SIZE(iscsi_session_state_names); i++) {
		if (iscsi_session_state_names[i].value == state) {
			name = iscsi_session_state_names[i].name;
			break;
		}


	NULL,
};

static umode_t iscsi_conn_attr_is_visible(struct kobject *kobj,
					 struct attribute *attr, int i)
{
	struct device *cdev = container_of(kobj, struct device, kobj);
	struct iscsi_cls_conn *conn = transport_class_to_conn(cdev);
	struct iscsi_transport *t = conn->transport;
	int param;

	if (attr == &dev_attr_conn_max_recv_dlength.attr)
		param = ISCSI_PARAM_MAX_RECV_DLENGTH;
	else if (attr == &dev_attr_conn_max_xmit_dlength.attr)
		param = ISCSI_PARAM_MAX_XMIT_DLENGTH;
	else if (attr == &dev_attr_conn_header_digest.attr)
		param = ISCSI_PARAM_HDRDGST_EN;
	else if (attr == &dev_attr_conn_data_digest.attr)
		param = ISCSI_PARAM_DATADGST_EN;
	else if (attr == &dev_attr_conn_ifmarker.attr)
		param = ISCSI_PARAM_IFMARKER_EN;
	else if (attr == &dev_attr_conn_ofmarker.attr)
		param = ISCSI_PARAM_OFMARKER_EN;
	else if (attr == &dev_attr_conn_address.attr)
		param = ISCSI_PARAM_CONN_ADDRESS;
	else if (attr == &dev_attr_conn_port.attr)
		param = ISCSI_PARAM_CONN_PORT;
	else if (attr == &dev_attr_conn_exp_statsn.attr)
		param = ISCSI_PARAM_EXP_STATSN;
	else if (attr == &dev_attr_conn_persistent_address.attr)
		param = ISCSI_PARAM_PERSISTENT_ADDRESS;
	else if (attr == &dev_attr_conn_persistent_port.attr)
		param = ISCSI_PARAM_PERSISTENT_PORT;
	else if (attr == &dev_attr_conn_ping_tmo.attr)
		param = ISCSI_PARAM_PING_TMO;
	else if (attr == &dev_attr_conn_recv_tmo.attr)
		param = ISCSI_PARAM_RECV_TMO;
	else if (attr == &dev_attr_conn_local_port.attr)
		param = ISCSI_PARAM_LOCAL_PORT;
	else if (attr == &dev_attr_conn_statsn.attr)
		param = ISCSI_PARAM_STATSN;
	else if (attr == &dev_attr_conn_keepalive_tmo.attr)
		param = ISCSI_PARAM_KEEPALIVE_TMO;
	else if (attr == &dev_attr_conn_max_segment_size.attr)
		param = ISCSI_PARAM_MAX_SEGMENT_SIZE;
	else if (attr == &dev_attr_conn_tcp_timestamp_stat.attr)
		param = ISCSI_PARAM_TCP_TIMESTAMP_STAT;
	else if (attr == &dev_attr_conn_tcp_wsf_disable.attr)
		param = ISCSI_PARAM_TCP_WSF_DISABLE;
	else if (attr == &dev_attr_conn_tcp_nagle_disable.attr)
		param = ISCSI_PARAM_TCP_NAGLE_DISABLE;
	else if (attr == &dev_attr_conn_tcp_timer_scale.attr)
		param = ISCSI_PARAM_TCP_TIMER_SCALE;
	else if (attr == &dev_attr_conn_tcp_timestamp_enable.attr)
		param = ISCSI_PARAM_TCP_TIMESTAMP_EN;
	else if (attr == &dev_attr_conn_fragment_disable.attr)
		param = ISCSI_PARAM_IP_FRAGMENT_DISABLE;
	else if (attr == &dev_attr_conn_ipv4_tos.attr)
		param = ISCSI_PARAM_IPV4_TOS;
	else if (attr == &dev_attr_conn_ipv6_traffic_class.attr)
		param = ISCSI_PARAM_IPV6_TC;
	else if (attr == &dev_attr_conn_ipv6_flow_label.attr)
		param = ISCSI_PARAM_IPV6_FLOW_LABEL;
	else if (attr == &dev_attr_conn_is_fw_assigned_ipv6.attr)
		param = ISCSI_PARAM_IS_FW_ASSIGNED_IPV6;
	else if (attr == &dev_attr_conn_tcp_xmit_wsf.attr)
		param = ISCSI_PARAM_TCP_XMIT_WSF;
	else if (attr == &dev_attr_conn_tcp_recv_wsf.attr)
		param = ISCSI_PARAM_TCP_RECV_WSF;
	else if (attr == &dev_attr_conn_local_ipaddr.attr)
		param = ISCSI_PARAM_LOCAL_IPADDR;
	else if (attr == &dev_attr_conn_state.attr)
		return S_IRUGO;
	else {
		WARN_ONCE(1, "Invalid conn attr");
		return 0;
	}


void iscsi_destroy_endpoint(struct iscsi_endpoint *ep)
{
	sysfs_remove_group(&ep->dev.kobj, &iscsi_endpoint_group);
	device_unregister(&ep->dev);
}


 *  %NULL on failure
 */
struct iscsi_bus_flash_session *
iscsi_create_flashnode_sess(struct Scsi_Host *shost, int index,
			    struct iscsi_transport *transport,
			    int dd_size)
{
	struct iscsi_bus_flash_session *fnode_sess;
	int err;

	fnode_sess = kzalloc(sizeof(*fnode_sess) + dd_size, GFP_KERNEL);
	if (!fnode_sess)
		return NULL;

	fnode_sess->transport = transport;
	fnode_sess->target_id = index;
	fnode_sess->dev.type = &iscsi_flashnode_sess_dev_type;
	fnode_sess->dev.bus = &iscsi_flashnode_bus;
	fnode_sess->dev.parent = &shost->shost_gendev;
	dev_set_name(&fnode_sess->dev, "flashnode_sess-%u:%u",
		     shost->host_no, index);

	err = device_register(&fnode_sess->dev);
	if (err)
		goto free_fnode_sess;

	if (dd_size)
		fnode_sess->dd_data = &fnode_sess[1];

	return fnode_sess;

free_fnode_sess:


}

static int
iscsi_set_host_param(struct iscsi_transport *transport,
		     struct iscsi_uevent *ev)
{
	char *data = (char*)ev + sizeof(*ev);
	struct Scsi_Host *shost;
	int err;

	if (!transport->set_host_param)
		return -ENOSYS;

	if (ev->u.set_host_param.len > PAGE_SIZE)
		return -EINVAL;

	shost = scsi_host_lookup(ev->u.set_host_param.host_no);
	if (!shost) {
		printk(KERN_ERR "set_host_param could not find host no %u\n",
		       ev->u.set_host_param.host_no);
		return -ENODEV;
	}

	err = transport->set_host_param(shost, ev->u.set_host_param.param,
					data, ev->u.set_host_param.len);


static void iscsi_iface_release(struct device *dev)
{
	struct iscsi_iface *iface = iscsi_dev_to_iface(dev);
	struct device *parent = iface->dev.parent;

	kfree(iface);
	put_device(parent);
}