commit - 2d331b3f3d70a5e5bf1362ff9e23627f0ca15288
commit + e84a83799e9828f1fe70428efafe33402a7572e8
blob - 08c1f3f3b37b555c2e7c4d573e06af93601a01d3
blob + 2c6b28c32e26056d4f1939cbe118d5492a29d10d
--- commands.c
+++ commands.c
static int pr_s_conf(int, char **);
static int pr_a_conf(int, char **);
static int pr_conf_diff(int, char **);
+static int pr_environment(int, char **);
static int show_hostname(int, char **);
static int wr_startup(void);
static int wr_conf(char *);
static int int_ssh(char *, int, int, char **);
static int int_telnet(char *, int, int, char **);
static int int_do(char *, int, int, char **);
+static int int_setenv(char *, int, int, char **);
+static int int_unsetenv(char *, int, int, char **);
static int int_show(char *, int, int, char **);
static int int_who(char *, int, int, char **);
static int int_doverbose(char *, int, int, char **);
static int manual(int, char**);
static int nocmd(int, char **);
static int docmd(int, char **);
+static int setenvcmd(int, char **);
+static int unsetenvcmd(int, char **);
static int shell(int, char*[]);
static int ping(int, char*[]);
static int ping6(int, char*[]);
{ "startup-config", "Startup configuration", CMPL0 0, 0, 0, 0, pr_s_conf },
{ "active-config", "Configuration of active context", CMPL0 0, 0, 0, 0, pr_a_conf },
{ "diff-config", "Show differences between startup and running config", CMPL0 0, 0, 0, 0, pr_conf_diff },
+ { "environment", "Show environment variables", CMPL(e) 0, 0, 0, 1, pr_environment },
{ "?", "Options", CMPL0 0, 0, 0, 0, show_help },
{ "help", 0, CMPL0 0, 0, 0, 0, show_help },
{ 0, 0, 0, 0, 0 }
static char showhelp[];
static char whohelp[];
static char dohelp[];
+static char setenvhelp[];
+static char unsetenvhelp[];
static char verbosehelp[];
static char editinghelp[];
static char shellhelp[];
{ "ssh", sshhelp, CMPL0 0, 0, int_ssh, 0 },
{ "telnet", telnethelp, CMPL0 0, 0, int_telnet, 0 },
{ "do", dohelp, CMPL(c) 0, 0, int_do, 0 },
+ { "setenv", setenvhelp, CMPL(e) 0, 0, int_setenv, 0 },
+ { "unsetenv", unsetenvhelp, CMPL(e) 0, 0, int_unsetenv, 0 },
{ "keepalive", "GRE tunnel keepalive", CMPL0 0, 0, intkeepalive, 1},
{ "mplslabel", "MPLS local label", CMPL0 0, 0, intmpls, 1 },
{ "pwe", "MPLS PWE3", CMPL0 0, 0, intpwe3, 1 },
{ "ssh", sshhelp, CMPL0 0, 0, int_ssh, 0 },
{ "telnet", telnethelp, CMPL0 0, 0, int_telnet, 0 },
{ "do", dohelp, CMPL(c) 0, 0, int_do, 0 },
+ { "setenv", setenvhelp, CMPL(e) 0, 0, int_setenv, 0 },
+ { "unsetenv", unsetenvhelp, CMPL(e) 0, 0, int_unsetenv, 0 },
{ "rule", "Bridge layer 2 filtering rules", CMPL0 0, 0, brrule, 0 },
{ "static", "Static bridge address entry", CMPL0 0, 0, brstatic, 1 },
{ "ifpriority", "Spanning priority of a member on an 802.1D bridge", CMPL0 0, 0, brpri, 1 },
int_do(char *ifname, int ifs, int argc, char **argv)
{
docmd(argc, argv);
+ return 0; /* do not leave interface context */
+}
+
+static int
+int_setenv(char *ifname, int ifs, int argc, char **argv)
+{
+ setenvcmd(argc, argv);
+ return 0; /* do not leave interface context */
+}
+
+static int
+int_unsetenv(char *ifname, int ifs, int argc, char **argv)
+{
+ unsetenvcmd(argc, argv);
return 0; /* do not leave interface context */
}
confighelp[] = "Set configuration mode",
whohelp[] = "Display system users",
dohelp[] = "Superfluous, do is ignored and its arguments executed",
+ setenvhelp[] = "Set an environment variable",
+ unsetenvhelp[] ="Delete an environment variable",
shellhelp[] = "Invoke a subshell",
savehelp[] = "Save the current configuration",
nreboothelp[] = "Reboot the system",
{ "sasyncd", "Search for tag sasyncd", CMPL0 NULL, 0 },
{ "scheduler", "Search for tag scheduler", CMPL0 NULL, 0 },
{ "sensor", "Search for tag sensor", CMPL0 NULL, 0 },
+ { "setenv", "Search for tag setenv", CMPL0 NULL, 0 },
{ "sh", "Search for tag sh", CMPL0 NULL, 0 },
{ "shell", "Search for tag shell", CMPL0 NULL, 0 },
{ "show", "Search for tag show", CMPL0 NULL, 0 },
{ "traceroute", "Search for tag traceroute", CMPL0 NULL, 0 },
{ "traceroute6", "Search for tag traceroute6", CMPL0 NULL, 0 },
{ "unprivileged", "Search for tag unprivileged", CMPL0 NULL, 0 },
+ { "unsetenv", "Search for tag setenv", CMPL0 NULL, 0 },
{ "veb", "Search for tag veb", CMPL0 NULL, 0 },
{ "verbose", "Search for tag verbose", CMPL0 NULL, 0 },
{ "vlan", "Search for tag vlan", CMPL0 NULL, 0 },
{ "who", whohelp, CMPL0 0, 0, who, 0, 0, 0, 0 },
{ "no", 0, CMPL(c) 0, 0, nocmd, 0, 0, 0, 0 },
{ "do", dohelp, CMPL(c) 0, 0, docmd, 0, 0, 0, 0 },
+ { "setenv", setenvhelp, CMPL(E) 0, 0, setenvcmd, 0, 0, 0, 0 },
+ { "unsetenv", unsetenvhelp, CMPL(e) 0, 0, unsetenvcmd, 0, 0, 0, 0 },
{ "!", shellhelp, CMPL0 0, 0, shell, 1, 0, 0, 0 },
{ "?", helphelp, CMPL(c) 0, 0, help, 0, 0, 0, 0 },
{ "manual", manhelp, CMPL(H) (char **)mantab, sizeof(struct ghs), manual,0, 0, 0, 0 },
return 0;
}
+static void
+usage_setenv(void)
+{
+ printf("%% setenv NAME=VALUE\n");
+ printf("%% setenv NAME=\"VALUE with spaces\"\n");
+ printf("%% setenv \"NAME with spaces\"=VALUE\n");
+}
+
+static int
+setenvcmd(int argc, char **argv)
+{
+ char *name = NULL, *value = NULL, *eq;
+
+ if (argc != 2) {
+ usage_setenv();
+ return 0;
+ }
+
+ eq = strchr(argv[1], '=');
+ if (eq == NULL) {
+ usage_setenv();
+ return 0;
+ }
+
+ name = strndup(argv[1], eq - argv[1]);
+ if (name == NULL) {
+ printf("%% setenvcmd: strndup: %s\n", strerror(errno));
+ return 0;
+ }
+
+ value = eq + 1;
+ if (setenv(name, value, 1) == -1)
+ printf("%% setenv %s=%s: %s\n", name, value, strerror(errno));
+
+ free(name);
+ return 0;
+}
+
+static int
+unsetenvcmd(int argc, char **argv)
+{
+ char *name;
+
+ if (argc != 2) {
+ printf("%% unsetenv NAME\n");
+ return 0;
+ }
+
+ name = argv[1];
+
+ if (unsetenv(name) == -1)
+ printf("%% unsetenv %s: %s\n", name, strerror(errno));
+
+ return 0;
+}
+
/*
* Shell command.
*/
}
printf("%% show dhcp leases\n");
return(1);
+}
+
+static int
+envcmp(const void *item1, const void *item2)
+{
+ const char *a = *(const char **)item1;
+ const char *b = *(const char **)item2;
+
+ return strcmp(a, b);
}
+
+static int
+pr_environment(int argc, char **argv)
+{
+ extern char **environ;
+ char **ep;
+ int fd;
+ char path[PATH_MAX];
+
+ if (strlcpy(path, "/tmp/nshrc.env.XXXXXXXX", sizeof(path)) >=
+ sizeof(path))
+ return 0;
+
+ fd = mkstemp(path);
+ if (fd == -1) {
+ printf("%% mkstemp %s: %s\n", path, strerror(errno));
+ return 0;
+ }
+
+ if (argc >= 3) {
+ char *name, *eq, *value;
+
+ name = argv[2];
+ for (ep = environ; *ep; ep++) {
+ eq = strchr(*ep, '=');
+ if (eq && strncmp(name, *ep, eq - *ep) == 0) {
+ value = eq + 1;
+ dprintf(fd, "%s\n", value);
+ break;
+ }
+ }
+ } else {
+ char **sorted_environ;
+ int nenv;
+
+ for (nenv = 0, ep = environ; *ep; ep++) {
+ if (strchr(*ep, '=') != NULL)
+ nenv++;
+ }
+
+ sorted_environ = calloc(nenv + 1, sizeof(*sorted_environ));
+ if (sorted_environ == NULL) {
+ printf("%% pr_environment: calloc: %s\n", strerror(errno));
+ goto done;
+ }
+
+ for (nenv = 0, ep = environ; *ep; ep++) {
+ if (strchr(*ep, '=') != NULL)
+ sorted_environ[nenv++] = *ep;
+ }
+
+ qsort(sorted_environ, nenv, sizeof(*sorted_environ), envcmp);
+ sorted_environ[nenv] = NULL;
+
+ for (ep = sorted_environ; *ep; ep++)
+ dprintf(fd, "%s\n", *ep);
+ }
+
+ fsync(fd);
+
+ more(path);
+done:
+ unlink(path);
+ close(fd);
+ return 0;
+}
blob - 1aa4e516adf58328b4cf0e36ccae19bbe005a6cc
blob + b3d3ffb85ca317f5281700df862ec443d010c534
--- complete.c
+++ complete.c
unsigned char complete(EditLine *, char **, size_t);
static int comparstr(const void *, const void *);
-static unsigned char complete_ambiguous(char *, int, StringList *, EditLine *);
+static unsigned char complete_ambiguous(char *, int, StringList *, EditLine *,
+ char *);
static unsigned char complete_command(char *, int, EditLine *, char **, int);
static unsigned char complete_subcommand(char *, int, EditLine *, char **, int);
static unsigned char complete_local(char *, int, EditLine *);
static unsigned char complete_ifgroup(char *, int, EditLine *);
static unsigned char complete_ifbridge(char *, int, EditLine *);
static unsigned char complete_rtable(char *, int, EditLine *);
+static unsigned char complete_environment(char *, int, EditLine *, int);
static unsigned char complete_nocmd(struct ghs *, char *, int, EditLine *,
char **, int, int);
static unsigned char complete_docmd(struct ghs *, char *, int, EditLine *,
* word word which started the match
* list list by default
* words stringlist containing possible matches
+ * sep separator to insert after completed word; usually " "
*/
static unsigned char
-complete_ambiguous(char *word, int list, StringList *words, EditLine *el)
+complete_ambiguous(char *word, int list, StringList *words, EditLine *el,
+ char *sep)
{
char insertstr[MAXPATHLEN];
char *lastmatch;
if (words->sl_cur == 1) { /* only one choice available */
(void)strlcpy(insertstr, words->sl_str[0], sizeof insertstr);
- (void)strlcat(insertstr, " ", sizeof insertstr);
+ (void)strlcat(insertstr, sep, sizeof insertstr);
if (el_insertstr(el, insertstr + wordlen) == -1)
return (CC_ERROR);
else
sl_add(words, ghs->name);
}
- rv = complete_ambiguous(word, list, words, el);
+ rv = complete_ambiguous(word, list, words, el, " ");
sl_free(words, 0);
return (rv);
}
}
closedir(dd);
- rv = complete_ambiguous(file, list, words, el);
+ rv = complete_ambiguous(file, list, words, el, " ");
sl_free(words, 1);
return (rv);
}
sl_add(words, s);
}
- rv = complete_ambiguous(word, list, words, el);
+ rv = complete_ambiguous(word, list, words, el, " ");
if_freenameindex(ifn_list);
sl_free(words, 0);
return (rv);
sl_add(words, ifg->ifgrq_group);
}
- rv = complete_ambiguous(word, list, words, el);
+ rv = complete_ambiguous(word, list, words, el, " ");
sl_free(words, 0);
free(ifgr.ifgr_groups);
close(ifs);
sl_add(words, ifnp->if_name);
}
- rv = complete_ambiguous(word, list, words, el);
+ rv = complete_ambiguous(word, list, words, el, " ");
if_freenameindex(ifn_list);
sl_free(words, 0);
close(ifs);
sl_add(words, rtable);
}
- rv = complete_ambiguous(word, list, words, el);
+ rv = complete_ambiguous(word, list, words, el, " ");
done:
sl_free(rtables, 1);
sl_free(words, 0);
return (rv);
}
+static unsigned char
+complete_environment(char *word, int dolist, EditLine *el, int set)
+{
+ StringList *words;
+ extern char **environ;
+ char **ep, *eq, *name;
+ size_t wordlen = strlen(word);
+ int rv = CC_ERROR;
+
+ words = sl_init();
+
+ for (ep = environ; *ep; ep++) {
+ eq = strchr(*ep, '=');
+ if (eq == NULL)
+ continue;
+ name = strndup(*ep, eq - *ep);
+ if (name == NULL) {
+ sl_free(words, 1);
+ return CC_ERROR;
+ }
+ if (strncmp(word, name, wordlen) == 0)
+ sl_add(words, name);
+ else
+ free(name);
+ }
+
+ /*
+ * When a new environment variable is created then hitting the
+ * TAB key makes '=' appear.
+ */
+ if (set && words->sl_cur == 0 && wordlen > 0 &&
+ word[wordlen - 1] != '=' && strchr(word, '=') == NULL) {
+ name = strdup(word);
+ if (name == NULL) {
+ sl_free(words, 1);
+ return CC_ERROR;
+ }
+ sl_add(words, name);
+ }
+
+ rv = complete_ambiguous(word, dolist, words, el, set ? "=" : " ");
+ sl_free(words, 1);
+ return rv;
+}
+
/*
* Generic complete routine
*/
return(CC_ERROR);
return (complete_showhelp(word, el, c->table, c->stlen, c->name,
help_vertical));
+ case 'E':
+ return complete_environment(word, dolist, el, 1);
+ case 'e':
+ return complete_environment(word, dolist, el, 0);
case 'n': /* no complete */
return (CC_ERROR);
}
blob - 1e1153b1ba8b2989aead1c19f5b9d61ee615af12
blob + 12f1978a735352ff8ea0aa9bb806d0832ed16d1a
--- nsh.8
+++ nsh.8
Display differences between the startup configuration and the running
configuration.
This command requires root user privileges.
+.Pp
+.Ic show environment Op Ar NAME
+.Pp
+Display environment variables.
+If the
+.Ar NAME
+of a variable is specified then display the value of this variable.
+Otherwise, display all existing environment variable names and values.
.Pp
+.Tg setenv
+.Ic setenv Ar NAME=VALUE
+.Pp
+Set the environment variable
+.Ar NAME
+to the specified
+.Ar VALUE.
+If a
+.Ar NAME
+or
+.Ar VALUE
+contains whitespace then it must be quoted in double-quotes.
+For example:
+.Bd -literal -offset indent
+nsh/setenv EDITOR=/usr/local/bin/emacs
+nsh/setenv MY_VARIABLE="this value contains whitespace"
+nsh/setenv "MY OTHER VARIABLE"=my-name-contains-whitespace
+.Ed
+.Pp
+.Tg unsetenv
+.Pp
+.Ic unsetenv Ar NAME
+.Pp
+Delete the variable
+.Ar NAME
+from the environment.
+.Pp
.Tg flush
.Ic flush
.Op routes | arp | ndp | line | bridge-dyn | bridge-all | bridge-rule | pf | history |\&? | help