All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dan Carpenter <dan.carpenter@oracle.com>
To: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
Cc: ksummit-discuss@lists.linuxfoundation.org,
	Michal Hocko <mhocko@kernel.org>
Subject: [Ksummit-discuss] [PATCH 2/2] kconfig: new command line kernel configuration tool
Date: Thu, 6 Jul 2017 17:42:08 +0300	[thread overview]
Message-ID: <20170706144208.6hlgxwo37gntk6qm@mwanda> (raw)
In-Reply-To: <20170706144028.46a2mt2mdzpt6ip7@mwanda>

This tool barely works, it's just a rough draft.

Sometimes I want to search for a config so I have to load menuconfig,
then search for the config entry, then exit.  With this script I
simply run:

    ./scripts/kconfig/kconfig search COMEDI

Quite often I find myself trying to enable a feature by doing this:

    echo CONFIG_FEATURE=y >> .config

But when I try to boot the new kernel, I find that the feature isn't
there because the kernel runs `make oldconfig` and I didn't have all
the depends selected so it silently removed it.  With this feature
what you can do is:

    ./scripts/kconfig/kconfig set FEATURE=y

It helps you enable the dependencies or it at least prints an error
if it can't enable the feature.

But this code isn't all implemented.  1) It doesn't calculate the
dependencies well.  See expr_parse() for more details.  2)  It
doesn't work well for things like:

	./scripts/kconfig/kconfig set BT_INTEL=m

because those aren't visible, they can only be using depend
statements.  Or say you try to set FEATURE=m when something else
depends on it be set =y then the error message is wrong.  The
other problem is that I don't know how to print the help text.
Again, this is just a rough draft.

Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
---
 scripts/kconfig/Makefile |   6 +-
 scripts/kconfig/kconfig  |  33 +++++
 scripts/kconfig/lconf.c  | 332 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 370 insertions(+), 1 deletion(-)
 create mode 100755 scripts/kconfig/kconfig
 create mode 100644 scripts/kconfig/lconf.c

diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index eb8144643b78..a2a90be2e149 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -33,6 +33,9 @@ config: $(obj)/conf
 nconfig: $(obj)/nconf
 	$< $(silent) $(Kconfig)
 
+lconfig: $(obj)/lconf
+	@ $< $(silent) $(Kconfig)
+
 silentoldconfig: $(obj)/conf
 	$(Q)mkdir -p include/config include/generated
 	$(Q)test -e include/generated/autoksyms.h || \
@@ -183,12 +186,13 @@ lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
 conf-objs	:= conf.o  zconf.tab.o
 mconf-objs     := mconf.o zconf.tab.o $(lxdialog)
 nconf-objs     := nconf.o zconf.tab.o nconf.gui.o
+lconf-objs     := lconf.o zconf.tab.o
 kxgettext-objs	:= kxgettext.o zconf.tab.o
 qconf-cxxobjs	:= qconf.o
 qconf-objs	:= zconf.tab.o
 gconf-objs	:= gconf.o zconf.tab.o
 
-hostprogs-y := conf nconf mconf kxgettext qconf gconf
+hostprogs-y := conf nconf mconf kxgettext qconf gconf lconf
 
 clean-files	:= qconf.moc .tmp_qtcheck .tmp_gtkcheck
 clean-files	+= zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h
diff --git a/scripts/kconfig/kconfig b/scripts/kconfig/kconfig
new file mode 100755
index 000000000000..beab8fc829c9
--- /dev/null
+++ b/scripts/kconfig/kconfig
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+usage() {
+	echo "kconfig [search|set] string"
+	exit 1;
+}
+
+if [ "$1" = "" ] ; then
+	usage
+fi
+
+if [ "$1" = "search" ] ; then
+
+	search=$2
+	NCONFIG_MODE=kconfig_search SEARCH=${search} make lconfig
+
+elif [ "$1" = "set" ] ; then
+
+	config=$2
+	setting=$3
+
+	if [ $config = "" ] ; then
+		echo "nothing to set"
+		exit 1
+	fi
+
+	NCONFIG_MODE=kconfig_set CONFIG=${config} SETTING=${setting} make lconfig
+
+else
+	usage
+fi
+
+
diff --git a/scripts/kconfig/lconf.c b/scripts/kconfig/lconf.c
new file mode 100644
index 000000000000..ebc3cbd4ef83
--- /dev/null
+++ b/scripts/kconfig/lconf.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2015 Oracle
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ */
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+
+#include "lkc.h"
+#include "nconf.h"
+#include <ctype.h>
+
+static int indent;
+static char line[128];
+
+static int get_depends(struct symbol *sym);
+
+static void strip(char *str)
+{
+	char *p = str;
+	int l;
+
+	while ((isspace(*p)))
+		p++;
+	l = strlen(p);
+	if (p != str)
+		memmove(str, p, l + 1);
+	if (!l)
+		return;
+	p = str + l - 1;
+	while ((isspace(*p)))
+		*p-- = 0;
+}
+
+static void xfgets(char *str, int size, FILE *in)
+{
+	if (fgets(str, size, in) == NULL)
+		fprintf(stderr, "\nError in reading or end of file.\n");
+}
+
+static tristate str_to_tristate(const char *str)
+{
+	switch (str[0]) {
+	case 'y': case 'Y':
+		return yes;
+	case 'm': case 'M':
+		return mod;
+	case 'n': case 'N':
+	default:
+		return no;
+	}
+}
+
+static int conf_askvalue(struct symbol *sym, const char *def)
+{
+	enum symbol_type type = sym_get_type(sym);
+
+	if (!sym_has_value(sym))
+		printf(_("(NEW) "));
+
+	line[0] = '\n';
+	line[1] = 0;
+
+	if (!sym_is_changable(sym)) {
+		printf("%s\n", def);
+		line[0] = '\n';
+		line[1] = 0;
+		return 0;
+	}
+
+	fflush(stdout);
+	xfgets(line, 128, stdin);
+
+	switch (type) {
+	case S_INT:
+	case S_HEX:
+	case S_STRING:
+		printf("%s\n", def);
+		return 1;
+	default:
+		;
+	}
+	printf("%s", line);
+	return 1;
+}
+
+static struct property *get_symbol_prop(struct symbol *sym)
+{
+	struct property *prop = NULL;
+
+	for_all_properties(sym, prop, P_SYMBOL)
+		break;
+	return prop;
+}
+
+static int conf_sym(struct symbol *sym)
+{
+	tristate oldval, newval;
+	struct property *prop;
+
+	while (1) {
+		if (sym->name)
+			printf("%s: ", sym->name);
+		for_all_prompts(sym, prop)
+			printf("%*s%s ", indent - 1, "",  _(prop->text));
+		putchar('[');
+		oldval = sym_get_tristate_value(sym);
+		switch (oldval) {
+		case no:
+			putchar('N');
+			break;
+		case mod:
+			putchar('M');
+			break;
+		case yes:
+			putchar('Y');
+			break;
+		}
+		if (oldval != no && sym_tristate_within_range(sym, no))
+			printf("/n");
+		if (oldval != mod && sym_tristate_within_range(sym, mod))
+			printf("/m");
+		if (oldval != yes && sym_tristate_within_range(sym, yes))
+			printf("/y");
+		/* FIXME: I don't know how to get the help text from the sym */
+		printf("] ");
+		if (!conf_askvalue(sym, sym_get_string_value(sym)))
+			return 0;
+		strip(line);
+
+		switch (line[0]) {
+		case 'n':
+		case 'N':
+			newval = no;
+			if (!line[1] || !strcmp(&line[1], "o"))
+				break;
+			continue;
+		case 'm':
+		case 'M':
+			newval = mod;
+			if (!line[1])
+				break;
+			continue;
+		case 'y':
+		case 'Y':
+			newval = yes;
+			if (!line[1] || !strcmp(&line[1], "es"))
+				break;
+			continue;
+		case 0:
+			newval = oldval;
+			break;
+		default:
+			continue;
+		}
+		if (sym_set_tristate_value(sym, newval)) {
+			/* FIXME: if I don't write it doesn't save */
+			conf_write(NULL, 1);
+			return 1;
+		}
+	}
+}
+
+static int enable_sym(struct symbol *sym)
+{
+	if (sym_get_tristate_value(sym) != no)
+		return 0;
+
+	if (!sym->visible) {
+		if (!get_depends(sym))
+			return 0;
+		printf("%s: has missing dependencies\n", sym->name);
+	}
+
+	return conf_sym(sym);
+}
+
+static void expr_parse(struct expr *e)
+{
+	if (!e)
+		return;
+
+	switch (e->type) {
+	case E_EQUAL:
+		printf("set '%s' to '%s'\n", e->left.sym->name, e->right.sym->name);
+		break;
+
+	case E_AND:
+		expr_parse(e->left.expr);
+		expr_parse(e->right.expr);
+		break;
+
+	case E_SYMBOL:
+		enable_sym(e->left.sym);
+		break;
+
+	case E_NOT:
+	case E_UNEQUAL:
+	case E_OR:
+	case E_LIST:
+	case E_RANGE:
+	default:
+		printf("HELP.  Lot of unimplemented code.  %d\n", e->type);
+		break;
+	}
+}
+
+static int get_depends(struct symbol *sym)
+{
+	struct property *prop;
+	struct gstr res = str_new();
+
+	prop = get_symbol_prop(sym);
+	if (!prop)
+		return 0;
+
+	expr_gstr_print(prop->visible.expr, &res);
+	printf("%s\n\n", str_get(&res));
+
+	expr_parse(prop->visible.expr);
+
+	return 1;
+}
+
+static void kconfig_search(void)
+{
+	char *search_str;
+	struct symbol **sym_arr;
+	struct gstr res;
+
+	search_str = getenv("SEARCH");
+	if (!search_str)
+		return;
+
+	sym_arr = sym_re_search(search_str);
+	res = get_relations_str(sym_arr, NULL);
+	printf("%s", str_get(&res));
+}
+
+static void kconfig_set(void)
+{
+	struct symbol *sym;
+	char *config;
+	char *setting;
+	int res;
+
+	config = getenv("CONFIG");
+	if (!config)
+		return;
+	if (strncmp(config, "CONFIG_", 7) == 0)
+		config += 7;
+
+	setting = strchr(config, '=');
+	if (setting) {
+		*setting = '\0';
+		setting++;
+	} else {
+		setting = getenv("SETTING");
+		if (setting && *setting == '\0')
+			setting = NULL;
+	}
+
+	sym = sym_find(config);
+	if (!sym) {
+		printf("Error: '%s' not found.\n", config);
+		return;
+	}
+
+	if (sym->curr.tri == str_to_tristate(setting)) {
+		printf("Already set:  %s=%s\n", sym->name, setting);
+		return;
+	}
+
+	if (!sym->visible) {
+		printf("\n%s: has missing dependencies\n", sym->name);
+		if (!get_depends(sym))
+			return;
+	}
+	if (!sym->visible) {
+		printf("Error: unmet dependencies\n");
+		return;
+	}
+
+	if (!setting) {
+		conf_sym(sym);
+	} else if (!sym_set_string_value(sym, setting)) {
+		printf("Error: setting '%s=%s' failed.\n", sym->name, setting);
+		return;
+	}
+
+	res = conf_write(NULL, 1);
+	if (res) {
+		printf("Error during writing of configuration.\n"
+			"Your configuration changes were NOT saved.\n");
+		return;
+	}
+
+	printf("set: %s=%s\n", config, sym_get_string_value(sym));
+}
+
+int main(int ac, char **av)
+{
+	char *mode;
+
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
+	if (ac > 1 && strcmp(av[1], "-s") == 0) {
+		/* Silence conf_read() until the real callback is set up */
+		conf_set_message_callback(NULL);
+		av++;
+	}
+	conf_parse(av[1]);
+	conf_read(NULL);
+
+	mode = getenv("NCONFIG_MODE");
+	if (!mode)
+		return 1;
+
+	if (strcmp(mode, "kconfig_search") == 0) {
+		kconfig_search();
+		return 0;
+	}
+	if (strcmp(mode, "kconfig_set") == 0) {
+		kconfig_set();
+		return 0;
+	}
+
+	return 1;
+}
-- 
2.11.0

  parent reply	other threads:[~2017-07-06 14:42 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-27 13:58 [Ksummit-discuss] [TECH TOPIC] is Kconfig a bit hard sometimes? Sergey Senozhatsky
2017-06-27 17:18 ` Linus Torvalds
2017-06-27 18:44   ` Luis R. Rodriguez
2017-06-27 19:27     ` Linus Torvalds
2017-06-27 20:53       ` Kees Cook
2017-06-27 21:16       ` Olof Johansson
2017-06-27 21:36         ` Linus Torvalds
2017-06-27 23:10           ` Serge E. Hallyn
2017-06-28  0:09             ` Luis R. Rodriguez
2017-06-28  0:14               ` Linus Torvalds
2017-06-28  0:26                 ` Luis R. Rodriguez
2017-06-28  3:54                   ` Stephen Hemminger
     [not found]                 ` <CAFhKne-o0S8fMo_XD_aUk2Rf7VbDhgO+PT_bjnM-9WpKfnWBvw@mail.gmail.com>
     [not found]                   ` <CAFhKne8FE=17wNdp=Svf2Z2tADok6htfYqTABEiZUrCOyeMaYg@mail.gmail.com>
2017-06-28 13:35                     ` Matthew Wilcox
2017-06-28 17:56                 ` Geert Uytterhoeven
2017-06-29 10:02                   ` Mauro Carvalho Chehab
2017-06-28  0:11             ` Linus Torvalds
2017-06-29 10:23           ` Mauro Carvalho Chehab
2017-06-28 12:58     ` Dan Carpenter
2017-06-30 17:11   ` Steven Rostedt
2017-06-30 17:52   ` Darren Hart
2017-06-30 17:58     ` Darren Hart
2017-07-01 17:24     ` Hannes Reinecke
2017-06-27 20:41 ` Kees Cook
2017-07-06 14:40 ` Dan Carpenter
2017-07-06 14:41   ` [Ksummit-discuss] [PATCH 1/2] kconfig: add a silent option to conf_write() Dan Carpenter
2017-07-06 15:08     ` Steven Rostedt
2017-07-06 14:42   ` Dan Carpenter [this message]
2017-07-07  5:55     ` [Ksummit-discuss] [PATCH 2/2] kconfig: new command line kernel configuration tool Krzysztof Kozlowski
2017-07-07  9:02       ` Dan Carpenter
2017-07-09  3:56         ` Linus Walleij
2017-07-09  8:31           ` Geert Uytterhoeven
2017-07-09 17:03             ` Randy Dunlap
2017-07-09 19:43               ` Geert Uytterhoeven
2017-07-09 17:32             ` Frank Rowand
2017-07-10  9:44     ` Geert Uytterhoeven
2017-07-10 11:15       ` Dan Carpenter
2017-07-06 16:41   ` [Ksummit-discuss] [TECH TOPIC] is Kconfig a bit hard sometimes? Linus Torvalds
2017-07-06 17:11     ` Randy Dunlap
2017-07-07 11:36     ` Dan Carpenter
2017-07-10 17:15       ` Luck, Tony
2017-07-10 17:33         ` Alexandre Belloni
2017-07-10 18:28           ` Linus Torvalds
2017-07-10 19:44             ` Randy Dunlap
2017-07-11  6:21             ` Valentin Rothberg
2017-07-06 21:19   ` Laurent Pinchart

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170706144208.6hlgxwo37gntk6qm@mwanda \
    --to=dan.carpenter@oracle.com \
    --cc=ksummit-discuss@lists.linuxfoundation.org \
    --cc=mhocko@kernel.org \
    --cc=sergey.senozhatsky.work@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.