How to control level of debugging info in glib? - c

I have a library written in C with glib/gobject. It produces significant number of debugging information via g_debug() call. This info is very helpful for troubleshooting, however I do not want it to be shown, when library is included with actual application. So, basically I need a way to control/filter amount of debugging information and I could not figure out how it supposed to work with glib. Could someone point me in the right direction, please?

You could try setting G_DEBUG environment variable as mentioned in the GLib developer site. Please refer to Environment variable section under Running and debugging GLib Applications in http://developer.gnome.org/glib/2.28/glib-running.html.
EDIT: Update to set the logger in the code.
You can use g_log_set_handler ( http://developer.gnome.org/glib/2.29/glib-Message-Logging.html#g-log-set-handler ) to do this in your code. Initially you can set the log handler to a dummy function which display nothings & then you can set the log handler to g_log_default_handler based on the argument passed for set appropriate log levels. To set the log levels above a set level you will need to manipulate GLogLevelFlags values as per your need.
Hope the below code sample will provide some pointers
#include <glib.h>
#include <stdio.h>
#include <string.h>
#define G_LOG_DOMAIN ((gchar*) 0)
static void _dummy(const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer user_data )
{
/* Dummy does nothing */
return ;
}
int main(int argc, char **argv)
{
/* Set dummy for all levels */
g_log_set_handler(G_LOG_DOMAIN, G_LOG_LEVEL_MASK, _dummy, NULL);
/* Set default handler based on argument for appropriate log level */
if ( argc > 1)
{
/* If -vv passed set to ONLY debug */
if(!strncmp("-vv", argv[1], 3))
{
g_log_set_handler(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, g_log_default_handler, NULL);
}
/* If -v passed set to ONLY info */
else if(!strncmp("-v", argv[1], 2))
{
g_log_set_handler(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, g_log_default_handler, NULL);
}
/* For everything else, set to back to default*/
else
{
g_log_set_handler(G_LOG_DOMAIN, G_LOG_LEVEL_MASK, g_log_default_handler, NULL);
}
}
else /* If no arguments then set to ONLY warning & critical levels */
{
g_log_set_handler(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING| G_LOG_LEVEL_CRITICAL, g_log_default_handler, NULL);
}
g_warning("This is warning\n");
g_message("This is message\n");
g_debug("This is debug\n");
g_critical("This is critical\n");
g_log(NULL, G_LOG_LEVEL_INFO , "This is info\n");
return 0;
}
Hope this helps!

I implemented custom log handler and here is how it turned out:
void custom_log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
{
gint debug_level = GPOINTER_TO_INT (user_data);
/* filter out messages depending on debugging level */
if ((log_level & G_LOG_LEVEL_DEBUG) && debug_level < MyLogLevel_DEBUG) {
return;
}
else if ((log_level & G_LOG_LEVEL_INFO) && debug_level < MyLogLevel_INFO) {
return;
}
g_printf ("%s\n", message);
}
int main(int argc, char *argv[])
{
...
if (verbose) {
g_log_set_handler (NULL, G_LOG_LEVEL_MASK, custom_log_handler, GINT_TO_POINTER (MyLogLevel_DEBUG));
}
else {
g_log_set_handler (NULL, G_LOG_LEVEL_MASK, custom_log_handler, GINT_TO_POINTER (MyLogLevel_NORMAL));
}
...
}
I hope it will be helpful to somebody :-)

You can control whether to print debug (log) messages with setting the G_MESSAGES_DEBUG environment variable when running your application.
The easiest is to use $ G_MESSAGES_DEBUG=all ./your-app when you need debugging (log) messages to be printed.
However, when G_MESSAGES_DEBUG=all glib libraries itself print debug (log) messages too which you may not need. So, predefine G_LOG_DOMAIN as a separate custom log domain string for your application and set G_MESSAGES_DEBUG to the same string when running. For example, use -DG_LOG_DOMAIN=\"my-app\" among compiler flags and run application with $ G_MESSAGES_DEBUG="my-app" ./your-app.

Related

Can you use struct XrmOptionDescRec array to pass non-Motif related parameters to an application?

I have seen how to configure xrm resource names via XrmOptionDescRec struct array. An example of this can be found in this question.
I am wondering if I can also pass non-X11 related arguments via this way.
In particular, if I want to pass the name of a named pipe to the application so the X11 application opens that particular named pipe,
would it be using XrmOptionDescRec struct array an option?
Can I set up and retrieve arbitrary resource names?
If so, how do I retrieve the argument value?
#include <stdlib.h>
#include <stdio.h>
#include <Xm/Xm.h>
#include <Xm/PushB.h>
static XrmOptionDescRec options[] = {
{ "-namedpipe", "namedpipe", XrmoptionSepArg, NULL },
};
int main(int argc, char *argv[]) {
Widget toplevel; /* Top Level Button */
XtAppContext app; /* Application Context */
char *window_title = NULL; /* Top Level Window Title */
/* INITIALIZE TOP LEVEL WINDOW */
XtSetLanguageProc(NULL, NULL, NULL);
toplevel = XtVaOpenApplication( &app, argv[0], options, XtNumber(options), &argc, argv, NULL, sessionShellWidgetClass, NULL);
/* HOW WOULD I GET HERE named_pipe ASSIGNED ????? */
char named_pipe[256];
...
/* REALIZE TOPLEVEL WINDOW AND LAUNCH APPLICATION LOOP */
XtRealizeWidget(toplevel);
XtAppMainLoop(app);
return 0;
}
Just for anyone interested. In Xt/Motif applications this seems to be the way to handle application command line parameters as resources (they have the advantage of being handled smoothly by the Xt wrappers around Xlib resource manager functions). So basically you will be able to define the argument in user, application and system-wide resource files, and also via command line.
#define XtNnamedPipe "namedPipe"
#define XtCNamedPipe "NamedPipe"
typedef struct {
String named_pipe;
} AppData;
AppData app_data;
static XtResource resources[] = {
{
XtNnamedPipe,
XtCNamedPipe,
XtRString,
sizeof(String),
XtOffsetOf(AppData, named_pipe),
XtRString,
NULL
},
};
static XrmOptionDescRec options[] = {
{"-namedpipe", "namedPipe", XrmoptionSepArg, "/tmp/namedpipe0"},
};
...
int main(int argc, char *argv[]) {
...
toplevel = XtVaOpenApplication(
&app, argv[0], options, XtNumber(options), &argc, argv, NULL, sessionShellWidgetClass,
XmNwidth, 400, XmNheight, 300, NULL
);
...
/* GET APPLICATION RESOURCES */
XtGetApplicationResources(
toplevel,
&app_data,
resources,
XtNumber(resources),
NULL,
0);
printf("DEBUG: %s\n", app_data.named_pipe);
...
}

How do I use clipboard in GTK?

How can I, using GtkClipboard, read and write to a clipboard? As an example, please show me how to get the current clipboard content and print it to console.
I tried this to get and print what is currently in the clipboard, but it doesn't work:
GtkClipboard *clip = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
gtk_clipboard_request_text(clip, (GtkClipboardTextReceivedFunc)print_clip, NULL);
Everything compiles without any warnings, but print_clip() function is never reached. Maybe I should use another function, like gtk_clipboard_wait_for_text()? Please help me, what am I supposed to do?
I use Linux/X11, if it matters. Also, I use GTK+3, not GTK+2 or some other release.
Ok, I've got a working example:
#include <gtk/gtk.h>
void clipboard_callback(GtkClipboard *clip, const gchar *text, gpointer data)
{
g_print("Now we're in clipboard_callback function.\n");
gtk_main_quit();
}
int main(int argc, char **argv)
{
gtk_init(&argc, &argv);
GtkClipboard *clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
gtk_clipboard_request_text(clip, clipboard_callback, NULL);
gtk_main();
return 0;
}
The only thing that I need now is to somehow exit clipboard_callback() without calling gtk_main_quit(), since that closes an application.
One should really use gtk_clipboard_wait_for_text() instead of gtk_clipboard_request_text().
For example, this is how it should be done:
GtkClipboard *clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
gchar *text = gtk_clipboard_wait_for_text(clip);
You can use below code from this link.
#include <gdk/gdk.h>
#include <gtk/gtk.h>
// This callback is invoked when the clipboard contents have been
// received. The text contents of the clipboard will be in UTF-8 in
// the `text` parameter.
void text_request_callback(GtkClipboard *clipboard,
const gchar *text,
gpointer data)
{
// To demonstrate setting a new value into the clipboard, we
// choose some text.
const gchar* new_clipboard_text = "Clipboard test 1";
if(text == 0 || g_utf8_collate(text, new_clipboard_text) == 0)
{
// If the program was already run, and the clipboard contains
// our string already, use a different string. This way when
// you run the program multiple times in a row, you'll see the
// string changing.
new_clipboard_text = "Clipboard test 2";
}
// This sets the text. I'm passing -1 because I'm lazy -- the
// function will call strlen on the string to figure out how long
// it is.
gtk_clipboard_set_text(clipboard, new_clipboard_text, -1);
// Display the content and the contents of the variable we passed
// in.
printf("Clipboard text was %s, value is %8X\n",
text, *(int*)data);
// Now that we've monkeyed with the clipboard, our job is done
// here.
gtk_main_quit();
}
int main(int argc, char** argv)
{
// Standard boilerplate: initialize the toolkit.
gtk_init(&argc, &argv);
// Get a handle to the given clipboard. You can also ask for
// GDK_SELECTION_PRIMARY (the X "primary selection") or
// GDK_SELECTION_SECONDARY.
GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
// This is just an arbitrary value to pass through to the
// callback. You could pass a pointer to a local struct or
// something similar if that was useful to you.
int value = 0xDECAFBAD;
// There are more complex things you can place in the clipboard,
// but this demonstrates text. The callback will be invoked when
// the clipboard contents has been received.
//
// For a much simpler method of getting the text in the clipboard,
// see gtk_clipboard_wait_for_text(), which is used in the example
// program clipboard_watch.
gtk_clipboard_request_text(clipboard, text_request_callback, &value);
// We have to run the GTK main loop so that the events required to
// fetch the clipboard contents can be processed.
gtk_main();
return 0;
}

Configure Parameters of LED Trigger from Kernel Space

I'm working on an embedded project. Our board is using Linux kernel v3.16.7. I'm working on supporting a couple of peripheral LEDs that monitor activity. I've successfully modified the boot procedure to load the drivers and create sysfs entries in /sys/class/leds/, which is great. I've also attached a oneshot trigger to the leds so I can echo 1 > shot from within /sys/class/leds/actled1\:green/ and the led blinks. Exactly what I want.
However, I want to configure the delays for each LED when I instantiate the driver during boot, and I'm not clear on how to do that. The driver creates sysfs entries in /sys/class/leds/actled1\:green/ called delay_on and delay_off, and I can write to them from userspace to configure the delays, but it should be possible to set their initial values from from kernel space during instantiation. I also want to be able to set the invert parameter (which is just another sysfs entry just like the delays).
How can I configure the parameters of an led trigger when I instantiate the driver from kernel space?
Below is how I instantiate the LED GPIOs. First I set up the structs required:
static struct gpio_led my_leds[] __initdata = {
{
.name = "actled1:green",
.default_trigger = "oneshot"
.gpio = ACTIVITY_LED_GPIO_BASE + 0,
.active_low = true,
},
{
.name = "actled2:red",
.default_trigger = "oneshot"
.gpio = ACTIVITY_LED_GPIO_BASE + 1,
.active_low = true,
},
};
static struct gpio_led_platform_data my_leds_pdata __initdata = {
.num_leds = ARRAY_SIZE(my_leds),
.leds = my_leds,
};
Then, I call this function to create the platform devices:
static int __init setup_my_leds (void)
{
struct platform_device *pdev;
int ret;
pdev = platform_device_alloc("leds-gpio", -1);
if (!pdev) {
return -ENOMEM;
}
ret = platform_device_add_data(pdev,
&my_leds_pdata,
sizeof(my_leds_pdata));
if (ret < 0) {
platform_device_put(pdev);
return ret;
}
ret = platform_device_add(pdev);
if (ret < 0) {
platform_device_put(pdev);
return ret;
}
return 0;
}
The definition for the gpio_led struct is in include/linux/leds.h line 327, and the definition for gpio_led_platform_data is in line 341 of the same file. The definition of platform_device_add_data is in drivers/base/platform.c line 284.
It may be useful to look at the source for the oneshot trigger (drivers/leds/trigger/ledtrig-oneshot.c) in order to answer the question. Also relevant is the "leds-gpio" driver (drivers/leds/leds-gpio.c).
I suspect the answer is somewhere in drivers/base/platform.c and the associated documentation, but I'm not seeing any functions that deal with the data I need.
To address some of the information that I inadvertently left out:
the boot loader sets the kernel arguments, and we can't modify the boot loader. that's fine; the values i want to set are constants and i can hard-code them in.
the driver is baked into the kernel at compile time (and, i presume, loaded by the bootloader) rather than loading a .ko with modprobe later.
i would love a general way to set arbitrary trigger parameters, not only oneshot's delay_on / delay_off. for example, oneshot's invert parameter.
i'm totally fine modifying oneshot / creating new triggers. in fact, once i get it working with oneshot, i'll need to create a new trigger that expands upon oneshot (which is also the reason i need to set arbitrary parameters).
There are a few issues and I think I've found the solutions, but even though you provided a good deal of info, there were some things missing, so I'll enumerate for all possible scenarios, so be patient ...
(1) Getting the initial values you want to set. I presume you have already figured this out, but ... You can get these from kernel cmdline parsing (e.g. you add the values to /boot/grub2/grub.cfg as myleds.delay_on=.... If you're loading via modprobe, you set a module parameter. These could also be a config file as in myleds.config_file=/etc/sysconfig/myleds.conf
(2) You could set them inside your setup_my_leds [except for the recalcitrance of oneshot_trig_activate--which we'll deal with soon enough]. From drivers/base/platform.c:
/**
* arch_setup_pdev_archdata - Allow manipulation of archdata before its used
* #pdev: platform device
*
* This is called before platform_device_add() such that any pdev_archdata may
* be setup before the platform_notifier is called. So if a user needs to
* manipulate any relevant information in the pdev_archdata they can do:
*
* platform_device_alloc()
* ... manipulate ...
* platform_device_add()
*
* And if they don't care they can just call platform_device_register() and
* everything will just work out.
*/
So, with that in mind, let's change your setup function slightly:
static int __init setup_my_leds (void)
{
struct platform_device *pdev;
int ret;
// get initial values you want to set, possibly storing away for later use
my_leds_get_init_values(...);
pdev = platform_device_alloc("leds-gpio", -1);
if (!pdev) {
return -ENOMEM;
}
// Choice (1): set your initial values in my_leds_pdata here
my_leds_set_init_values(&my_leds_pdata);
// NOTE: just does kmemdup and sets pdev->dev.platform_data
ret = platform_device_add_data(pdev,
&my_leds_pdata,
sizeof(my_leds_pdata));
if (ret < 0) {
platform_device_put(pdev);
return ret;
}
// Choice (2): set your initial values in pdev->dev.platform_data here
my_leds_set_init_values(pdev->dev.platform_data);
ret = platform_device_add(pdev);
if (ret < 0) {
platform_device_put(pdev);
return ret;
}
return 0;
}
(3) Unfortunately, since you're using .default_trigger = "oneshot", the above data will get blasted by oneshot_trig_activate in drivers/leds/trigger/ledtrig-oneshot.c. So, we need to deal with that.
Option (A): Assuming you can rebuild the whole kernel as you choose, just modify oneshot_trig_activate in ledtrig-oneshot.c and remove the the lines that use DEFAULT_DELAY. This is only really useful if you know that it's not used by anything else in your system that might need the default values.
Option (B): If you're not allowed to modify ledtrig-oneshot.c, but are allowed to add new triggers to drivers/leds/trigger, copy the file to (e.g.) ledtrig-oneshot2.c and do the changes there. You'll need to change the .name to .name = "oneshot2". The easy way [in vi, of course :-)] is :%s/oneshot/oneshot2/g. You'll also need to add a new entry in the Kconfig and Makefile for this. Then, change your struct definition to use the new driver: .default_trigger = "oneshot2"
Option (C): Assuming you can't [or don't want to] touch the drivers/leds/trigger directory, copy ledtrig-oneshot.c to your driver directory [renaming as appropriate]. Do the edits from option (B) above there. With some trickery in your Makefile, you can get it to build both my_led_driver.ko and ledtrig-oneshot2.ko. You'll need modify your Kconfig, possibly adding a depends on LED_TRIGGERS for the led trigger driver. You could also put the two into separate subdirectories and the individual Makefile/Kconfig might be simpler: my_led/my_driver and my_led/my_trigger
Option (C) would be more work up front, but might be cleaner and more portable in the long run. Of course, you could do option (A) for proof-of-concept, then do option (B), and do the "final ship" as option (C).
An alternate way for when you set the initial values: Remember the comment for my_leds_get_init_values was possibly storing away for later use. You could change oneshot2_trig_activate to call it instead of using DEFAULT_DELAY. I don't like this quite as much and prefer the solutions that simply neuter oneshot_trig_activate's offensive behavior. But, with some testing, you may find that this is the way you have to do it.
Hopefully, the above will work. If not, edit your question with additional info and/or restrictions [and send me a comment], and I'll be glad to update my answer [I've been doing drivers for 40+].
UPDATE: Okay, herein is a fully annotated and modified LED trigger driver that you can use as a drop in replacement for drivers/led/trigger/ledtrig-oneshot.c.
Because the invert parameter can not be passed directly through any standard struct you have access to in your setup function [i.e. it's stored in a private struct inside the trigger driver], remove the "Choice (1)" and "Choice (2)". We'll set them all at once inside the [modified] oneshot_trig_activate.
Also, the init parameters you want must be set up and stored as globals by the my_leds_get_init_values so the trigger driver can find them. That is, there is no way to do this cleanly (e.g. with a pointer to a private struct that gets passed around) as the structs you have access to in setup don't have a field for this. See the top part of the trigger driver for discussion on this.
My first step was to annotate the base driver with descriptive comments. There were no comments in it, except for K&R style for copyright and a single one-liner. My annotations are ANSI ("//") comments.
If I were taking over the driver, I would add these and leave them in. However, my level of comments might be considered "over-commenting" according to the kernel style guide and might be considered "cruft", particularly for a driver that is this straightforward.
Next step was to add the necessary changes. All places that have additions/changes are marked with a comment block that starts with "C:". These are the important places to look. Note that these comments are legitimate candidates to leave in. In other more complex drivers, the level of commenting is up to the author. The "C:" is just to highlight the places for you.
With the annotations, a straight line read through might be easier now. Also, a diff -u might also help. If you've got everything under git, so much the better.
Because of all this, I'd remove the "Option (A)" [direct modification of the original file] and do "Option (B)" or "Option (C)" only.
The trigger driver uses all static definitions, so the global edit I suggested before is not needed. I did do .name = "myled_oneshot";, so you'll need to match that with .default_trigger = "myled_oneshot";. Feel free to use my_leds_whatever to be consistent with your existing naming convention. When I do this for myself, I usually use my initials, so it becomes ce_leds_whatever--YMMV
Anyway, here's the entire modified trigger driver. Note that I've done the editing, but I've not tried to compile/build it.
/*
* One-shot LED Trigger
*
* Copyright 2012, Fabio Baltieri <fabio.baltieri#gmail.com>
*
* Based on ledtrig-timer.c by Richard Purdie <rpurdie#openedhand.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/ctype.h>
#include <linux/slab.h>
#include <linux/leds.h>
#include "../leds.h"
// C: we need to get access to the init data populated by the setup function
// we have the "clean way" with a struct definition inside a header file and
// the "dirty way" using three separate int globals
// in either case, the externs referenced here must be defined in the "my_leds"
// driver as global
// C: the "clean way"
// (1) requires that we have a path to the .h (e.g. -I<whatever)
// (2) this would be easier/preferable for the "Option (C)"
// (3) once done, easily extensible [probably not a consideration here]
#ifdef MYLED_USESTRUCT
#include "whatever/myled_init.h"
extern struct myled_init myled_init;
// C: the "ugly way"
// (1) no need to use a separate .h file
// (2) three separate global variables is wasteful
// (3) more than three, and we really should consider the "struct"
#else
extern int myled_init_delay_on;
extern int myled_init_delay_off;
extern int myled_init_invert;
#endif
#define DEFAULT_DELAY 100
// oneshot trigger driver private data
struct oneshot_trig_data {
unsigned int invert; // current invert state
};
// arm oneshot sequence from sysfs write to shot file
static ssize_t led_shot(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
led_blink_set_oneshot(led_cdev,
&led_cdev->blink_delay_on, &led_cdev->blink_delay_off,
oneshot_data->invert);
/* content is ignored */
return size;
}
// show invert state for "cat invert"
static ssize_t led_invert_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
return sprintf(buf, "%u\n", oneshot_data->invert);
}
// set invert from sysfs write to invert file (e.g. echo 1 > invert)
static ssize_t led_invert_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
unsigned long state;
int ret;
ret = kstrtoul(buf, 0, &state);
if (ret)
return ret;
oneshot_data->invert = !!state;
if (oneshot_data->invert)
led_set_brightness_async(led_cdev, LED_FULL);
else
led_set_brightness_async(led_cdev, LED_OFF);
return size;
}
// show delay_on state for "cat delay_on"
static ssize_t led_delay_on_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
return sprintf(buf, "%lu\n", led_cdev->blink_delay_on);
}
// set delay_on from sysfs write to delay_on file (e.g. echo 20 > delay_on)
static ssize_t led_delay_on_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
unsigned long state;
int ret;
ret = kstrtoul(buf, 0, &state);
if (ret)
return ret;
led_cdev->blink_delay_on = state;
return size;
}
// show delay_off state for "cat delay_off"
static ssize_t led_delay_off_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
return sprintf(buf, "%lu\n", led_cdev->blink_delay_off);
}
// set delay_off from sysfs write to delay_off file (e.g. echo 20 > delay_off)
static ssize_t led_delay_off_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
unsigned long state;
int ret;
ret = kstrtoul(buf, 0, &state);
if (ret)
return ret;
led_cdev->blink_delay_off = state;
return size;
}
// these are the "attribute" definitions -- one for each sysfs entry
// pointers to these show up in the above functions as the "attr" argument
static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store);
static DEVICE_ATTR(shot, 0200, NULL, led_shot);
// activate the trigger device
static void oneshot_trig_activate(struct led_classdev *led_cdev)
{
struct oneshot_trig_data *oneshot_data;
int rc;
// create an instance of the private data we need
oneshot_data = kzalloc(sizeof(*oneshot_data), GFP_KERNEL);
if (!oneshot_data)
return;
// save the pointer in the led class struct so it's available to other
// functions above
led_cdev->trigger_data = oneshot_data;
// attach the sysfs entries
rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
if (rc)
goto err_out_trig_data;
rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
if (rc)
goto err_out_delayon;
rc = device_create_file(led_cdev->dev, &dev_attr_invert);
if (rc)
goto err_out_delayoff;
rc = device_create_file(led_cdev->dev, &dev_attr_shot);
if (rc)
goto err_out_invert;
// C: this is what the driver used to do
#if 0
led_cdev->blink_delay_on = DEFAULT_DELAY;
led_cdev->blink_delay_off = DEFAULT_DELAY;
#endif
led_cdev->activated = true;
// C: from here to the return is what the modified driver must do
#ifdef MYLED_USESTRUCT
led_cdev->blink_delay_on = myled_init.delay_on;
led_cdev->blink_delay_off = myled_init.delay_off;
oneshot_data->invert = myled_init.invert;
#else
led_cdev->blink_delay_on = myled_init_delay_on;
led_cdev->blink_delay_off = myled_init_delay_off;
oneshot_data->invert = myled_init_invert;
#endif
// C: if invert is off, nothing to do -- just like before
// if invert is set, we implement this as if we just got an instantaneous
// write to the sysfs "invert" file (which would call led_invert_store
// above)
// C: this is a direct rip-off of the above led_invert_store function which
// we can _not_ call here directly because we don't have access to the
// data it needs for its arguments [at least, not conveniently]
// so, we extract the one line we actually need
if (oneshot_data->invert)
led_set_brightness_async(led_cdev, LED_FULL);
return;
// release everything if an error occurs
err_out_invert:
device_remove_file(led_cdev->dev, &dev_attr_invert);
err_out_delayoff:
device_remove_file(led_cdev->dev, &dev_attr_delay_off);
err_out_delayon:
device_remove_file(led_cdev->dev, &dev_attr_delay_on);
err_out_trig_data:
kfree(led_cdev->trigger_data);
}
// deactivate the trigger device
static void oneshot_trig_deactivate(struct led_classdev *led_cdev)
{
struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
// release/destroy all the sysfs entries [and free the private data]
if (led_cdev->activated) {
device_remove_file(led_cdev->dev, &dev_attr_delay_on);
device_remove_file(led_cdev->dev, &dev_attr_delay_off);
device_remove_file(led_cdev->dev, &dev_attr_invert);
device_remove_file(led_cdev->dev, &dev_attr_shot);
kfree(oneshot_data);
led_cdev->activated = false;
}
/* Stop blinking */
led_set_brightness(led_cdev, LED_OFF);
}
// definition/control for trigger device registration
// C: changed the name to "myled_oneshot"
static struct led_trigger oneshot_led_trigger = {
.name = "myled_oneshot",
.activate = oneshot_trig_activate,
.deactivate = oneshot_trig_deactivate,
};
// module init function -- register the trigger device
static int __init oneshot_trig_init(void)
{
return led_trigger_register(&oneshot_led_trigger);
}
// module exit function -- unregister the trigger device
static void __exit oneshot_trig_exit(void)
{
led_trigger_unregister(&oneshot_led_trigger);
}
module_init(oneshot_trig_init);
module_exit(oneshot_trig_exit);
MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri#gmail.com>");
MODULE_DESCRIPTION("One-shot LED trigger");
MODULE_LICENSE("GPL");
As you can see in ledtrig-oneshot.c, the delay is always initialized with DEFAULT_DELAY. Unfortunately, if you want to be able to configure a different value at startup, this is a mechanism you will have to implement..
As Craig answered it should be from kernel command line options, but there could be a problem with embedded systems where the boot-loader passes the command line parameters and the boot-loaders cannot be modified, they are usually OTP . In that case I see only 2 options
hard coding in the kernel init function
as mac address is stored in eeprom for the nic driver to read, if the values can be stored in a flash (nor) and the value read on boot. This can be done after creating the mtd partitions during kernel boot.

Pass command line argument to a sub function

I have a C program main routine which calls heirarchically several levels of functions. Eg :
main -> MyFunc -> MySubFunc -> MySub2Func
and I have a condition in MySub2Func which needs to be checked against a command line argument. Eg:
if (myvar == argv[1])
Other than passing argv as a parameter to subfunction , is there any other way I could acheive this. (because I need to do this in several functions lying at different heirarchical levels)
Each of the sub-functions lie in different C files. My aim is to perform a debug by temporarily checking a particular local variable against a cmd line argument (and taking further actions accordingly) .. hence modifying the entire heirarchy is unfortunately not desirable for my purpose.
[update from comment]
sorry that I forgot to mention .. i am trying to perform a debug by temporarily checking a particular local variable against a cmd line argument (and taking further actions accordingly) .. hence modifying the entire heirarchy is unfortunately not desirable for my purpose ..
The common approach is to "decouple" the two; the functions further down the call tree really shouldn't care or know about main()'s arguments, i.e. the command argument vector itself.
Instead, it should be abstracted into application-specific options, which are passed from main(), which parses the options out of the command line arguments, down to all application-specific functions that need them.
You might use global variables that are set in the main() function:
int g_argc;
char **g_argv;
int main(int argc, char **argv) {
g_argc = argc;
g_argv = argv;
MyFunc();
}
...
void MyFunc() {
MySubFunc();
}
...
void MySubFunc() {
MySub2Func();
}
...
void MySub2Func() {
if (myvar == g_argv[1]) {
do_the_thing();
}
}
As unwind said, the functions further down the chain should really not know anything about main's arguments. You should parse the command line arguments once setting the program's configuration. Additionally you should provide query functions for this configuration e.g.
/* --- config.c */
typedef struct {
int debug_enabled;
} config_t;
static config_t configuration;
int debug_enabled() {
return configuration->debug_enabled;
}
void initialize_config() {
/* set default parameters */
}
int set_config_from_cmd(int argc, char** argv){
/* parse CMD parameters and set config */
}
/* --- main.c */
int main(int argc, char** argv)
{
initialize_config();
if ( set_config_from_cmd(argc, argv) == -1 ) {
exit(-1);
}
/* do stuff, call functions */
}
int myfunction() {
if ( debug_enabled() ) {
printf("debug!");
}
/* do stuff */
}
Notice that I put the configuration related stuff into a separate file in order to hide the internals of the configuration structure. Only the interface e.g. debug_enabled() etc is exposed.
[for debugging]
Put this in a header included by all modules involved:
extern int g_argc;
extern char ** g_argv;
Define g_argc and g_argv globally in the main module
int g_argc = 0;
char ** g_argv = NULL;
Then in main() just do
int main(int argv, char ** argv)
{
g_argc = argc;
g_argv = argv;
and access g_argc and g_argv from the modules in question.

Change Struct module pointer

Good day all, I'd like some help to change a small section in this C program which I have licensed back in the early 90's. Some of you may be familiar with it, it's called MajorBBS and as you probably have guess it is bbs software.
In the header file majorbbs.h we have
extern
struct module { /* module interface block */
char descrp[MNMSIZ]; /* description for main menu */
int (*lonrou)(); /* user logon supplemental routine */
int (*sttrou)(); /* input routine if selected */
void (*stsrou)(); /* status-input routine if selected */
int (*injrou)(); /* "injoth" routine for this module */
int (*lofrou)(); /* user logoff supplemental routine */
void (*huprou)(); /* hangup (lost carrier) routine */
void (*mcurou)(); /* midnight cleanup routine */
void (*dlarou)(); /* delete-account routine */
void (*finrou)(); /* finish-up (sys shutdown) routine */
} **module;
Also in the majorbbs.h we have some code that defines the menu variables
extern
struct usrmnu { /* user's menuing-specific variables */
char curpag[PNMSIZ]; /* current menu page */
char parpag[PNMSIZ]; /* parent menu page */
char selchrs[MAXSEL]; /* select characters currently available */
char pages[MAXSEL][PNMSIZ]; /* pages or file names for select chars */
char optdsp[MAXSEL]; /* instructions on how to display options */
int keyreq[MAXSEL]; /* key required for each select character */
FILE *fp; /* pointer to file currently being viewed */
char mnuttl[TITLSZ]; /* menu page title */
} *mnuusr;
Then in the majorbbs.c file we have
struct module module00={ /* module interface block */
"Menuing System", /* description for main menu */
NULL, /* user logon supplemental routine */
mainu, /* input routine if selected */
musthn, /* status-input routine if selected */
NULL, /* "injoth" routine for this module */
NULL, /* user logoff supplemental routine */
loscar, /* hangup (lost carrier) routine */
midnit, /* midnight cleanup routine */
NULL, /* delete-account routine */
mjrfin /* finish-up (sys shutdown) routine */
};
What I'd like is to change the value of the descrp here which is defined as "Menuing System" to something more dynamic like the Menu the user is currently on.
From the code here I think it would be mnuusr->curpag which is where the pointer is pointing to I think.
So I'm thinking of a routine. I am by no means a programmer and I've been there many sites to look for examples of how to do such a thing. I've searched here for the last couple days (before posting this). I saw some things
that sparked a "Hey this might work" but I ended up with compiler errors (more on that in a bit)
What I did was make a routine like
char *
mydescrp
{
if (strcmp(module00.descrp,"Menuing System" ) == 0 ) {
mnuusr=mnuoff(usrnum);
return(mnuusr->mnuttl);
}
}
Then if I change the module00 call above to
struct module module00={
mydescrp, /* My change */
NULL,
mainu,
musthn,
NULL,
NULL,
loscar,
midnit,
NULL,
mjrfin
};
When I compile I get some error that says:
Initalization not fully bracketed
the list goes on from there. There are some further initialization later on in majorbbs.c and will gladly supply them if you need. I am sure one would be.
int
register_module( /* register a module for online use */
struct module *mod) /* pointer to a module block */
{
if (strlen(mod->descrp) > MNMSIZ-1) {
catastro("MODULE NAME \"%s\" TOO LONG!",mod->descrp);
}
if (mod->stsrou == NULL) {
mod->stsrou=dfsthn;
}
if (nmods == 0) {
module=(struct module **)alcmem(sizeof(struct module *));
mdstats=(struct mdstats *)alcmem(sizeof(struct mdstats));
}
else {
module=(struct module **)alcrsz(module,sizeof(struct module *)*nmods,
sizeof(struct module *)*(nmods+1));
mdstats=(struct mdstats *)alcrsz(mdstats,sizeof(struct mdstats)*nmods,
sizeof(struct mdstats)*(nmods+1));
}
module[nmods]=mod;
setbtv(mstbb);
if (qeqbtv(mod->descrp,0)) {
gcrbtv(&mdstats[nmods],0);
}
else {
setmem(&mdstats[nmods],sizeof(struct mdstats),0);
strcpy(mdstats[nmods].mdname,mod->descrp);
}
rstbtv();
return(nmods++);
}
From MENUING.C mnuoff routine
struct usrmnu *
mnuoff( /* get pointer to user's menu info */
int unum) /* user number to grab */
{
#ifdef PHARLAP
return((struct usrmnu *)((long)(eclmnubas+(unum<<3))<<16));
#else
#ifdef ECLIPSE
return((struct usrmnu *)((long)(eclmnubas+(unum<<3))<<16));
#else
return((struct usrmnu *)(muusrs+(unum*(long)sizeof(struct usrmnu))));
#endif
#endif
}
Is this the routine to change for some newly code? I am simply at a loss on how to go about this. If you need more code let me know.
I even went as far as asking for help from other majorbbs programmers on usenet but this software is 20 years + old so I don't think anyone uses it anymore let alone modify code anymore. I would think since it's still C someone might have an idea to help me out. I am trying to create a new revive with some small modifications. This being one of two.
Thanks for any help.
It looks like the descrp field in struct module is expecting a char[] (or a string), and you're giving it a char *() (function returning a string) instead.
Perhaps what you want to do is not call the mydescrp function in the declaration of module00, but manually perform the check in register_module:
int register_module(struct module *mod) {
if (strcmp(mod->descrp, "Menuing System") == 0) {
struct usrmnu *menu = mnuoff(usrnum);
// Copy as much of the title to the menu description as possible.
strncpy(mod->descrp, menu->mnuttl, MNMSIZ-1);
// Terminate the string in case the title was too long.
mod->descrp[MNMSIZ-1] = '\0';
}
// Rest of method.
}

Resources