Find pathname from dlopen handle on OSX - c

I have dlopen()'ed a library, and I want to invert back from the handle it passes to me to the full pathname of shared library. On Linux and friends, I know that I can use dlinfo() to get the linkmap and iterate through those structures, but I can't seem to find an analogue on OSX. The closest thing I can do is to either:
Use dyld_image_count() and dyld_get_image_name(), iterate over all the currently opened libraries and hope I can guess which one corresponds to my handle
Somehow find a symbol that lives inside of the handle I have, and pass that to dladdr().
If I have apriori knowledge as to a symbol name inside of the library I just opened, I can dlsym() that and then use dladdr(). That works fine. But in the general case where I have no idea what is inside this shared library, I would need to be able to enumerate symbols to do that, which I don't know how to do either.
So any tips on how to lookup the pathname of a library from its dlopen handle would be very much appreciated. Thanks!

Here is how you can get the absolute path of a handle returned by dlopen.
In order to get the absolute path, you need to call the dladdr function and retrieve the Dl_info.dli_fname field.
In order to call the dladdr function, you need to give it an address.
In order to get an address given a handle, you have to call the dlsym function with a symbol.
In order to get a symbol out of a loaded library, you have to parse the library to find its symbol table and iterate over the symbols. You need to find an external symbol because dlsym only searches for external symbols.
Put it all together and you get this:
#import <dlfcn.h>
#import <mach-o/dyld.h>
#import <mach-o/nlist.h>
#import <stdio.h>
#import <string.h>
#ifdef __LP64__
typedef struct mach_header_64 mach_header_t;
typedef struct segment_command_64 segment_command_t;
typedef struct nlist_64 nlist_t;
#else
typedef struct mach_header mach_header_t;
typedef struct segment_command segment_command_t;
typedef struct nlist nlist_t;
#endif
static const char * first_external_symbol_for_image(const mach_header_t *header)
{
Dl_info info;
if (dladdr(header, &info) == 0)
return NULL;
segment_command_t *seg_linkedit = NULL;
segment_command_t *seg_text = NULL;
struct symtab_command *symtab = NULL;
struct load_command *cmd = (struct load_command *)((intptr_t)header + sizeof(mach_header_t));
for (uint32_t i = 0; i < header->ncmds; i++, cmd = (struct load_command *)((intptr_t)cmd + cmd->cmdsize))
{
switch(cmd->cmd)
{
case LC_SEGMENT:
case LC_SEGMENT_64:
if (!strcmp(((segment_command_t *)cmd)->segname, SEG_TEXT))
seg_text = (segment_command_t *)cmd;
else if (!strcmp(((segment_command_t *)cmd)->segname, SEG_LINKEDIT))
seg_linkedit = (segment_command_t *)cmd;
break;
case LC_SYMTAB:
symtab = (struct symtab_command *)cmd;
break;
}
}
if ((seg_text == NULL) || (seg_linkedit == NULL) || (symtab == NULL))
return NULL;
intptr_t file_slide = ((intptr_t)seg_linkedit->vmaddr - (intptr_t)seg_text->vmaddr) - seg_linkedit->fileoff;
intptr_t strings = (intptr_t)header + (symtab->stroff + file_slide);
nlist_t *sym = (nlist_t *)((intptr_t)header + (symtab->symoff + file_slide));
for (uint32_t i = 0; i < symtab->nsyms; i++, sym++)
{
if ((sym->n_type & N_EXT) != N_EXT || !sym->n_value)
continue;
return (const char *)strings + sym->n_un.n_strx;
}
return NULL;
}
const char * pathname_for_handle(void *handle)
{
for (int32_t i = _dyld_image_count(); i >= 0 ; i--)
{
const char *first_symbol = first_external_symbol_for_image((const mach_header_t *)_dyld_get_image_header(i));
if (first_symbol && strlen(first_symbol) > 1)
{
handle = (void *)((intptr_t)handle | 1); // in order to trigger findExportedSymbol instead of findExportedSymbolInImageOrDependentImages. See `dlsym` implementation at http://opensource.apple.com/source/dyld/dyld-239.3/src/dyldAPIs.cpp
first_symbol++; // in order to remove the leading underscore
void *address = dlsym(handle, first_symbol);
Dl_info info;
if (dladdr(address, &info))
return info.dli_fname;
}
}
return NULL;
}
int main(int argc, const char * argv[])
{
void *libxml2 = dlopen("libxml2.dylib", RTLD_LAZY);
printf("libxml2 path: %s\n", pathname_for_handle(libxml2));
dlclose(libxml2);
return 0;
}
If you run this code, it will yield the expected result: libxml2 path: /usr/lib/libxml2.2.dylib

After about a year of using the solution provided by 0xced, we discovered an alternative method that is simpler and avoids one (rather rare) failure mode; specifically, because 0xced's code snippet iterates through each dylib currently loaded, finds the first exported symbol, attempts to resolve it in the dylib currently being sought, and returns positive if that symbol is found in that particular dylib, you can have false positives if the first exported symbol from an arbitrary library happens to be present inside of the dylib you're currently searching for.
My solution was to use _dyld_get_image_name(i) to get the absolute path of each image loaded, dlopen() that image, and compare the handle (after masking out any mode bits set by dlopen() due to usage of things like RTLD_FIRST) to ensure that this dylib is actually the same file as the handle passed into my function.
The complete function can be seen here, as a part of the Julia Language, with the relevant portion copied below:
// Iterate through all images currently in memory
for (int32_t i = _dyld_image_count(); i >= 0 ; i--) {
// dlopen() each image, check handle
const char *image_name = _dyld_get_image_name(i);
uv_lib_t *probe_lib = jl_load_dynamic_library(image_name, JL_RTLD_DEFAULT);
void *probe_handle = probe_lib->handle;
uv_dlclose(probe_lib);
// If the handle is the same as what was passed in (modulo mode bits), return this image name
if (((intptr_t)handle & (-4)) == ((intptr_t)probe_handle & (-4)))
return image_name;
}
Note that functions such as jl_load_dynamic_library() are wrappers around dlopen() that return libuv types, but the spirit of the code remains the same.

Related

Tcl pathInFilesystemProc get current filesystem

When creating a vfs using the tcl api how do you get the current filesystem in Tcl_Filesystem.pathInFilesystemProc
My code looks something like this:
typedef struct {
FILE* dbFile;
/*...*/
} FSBackend;
void createFS(const char* dbFile)
{
FSBackend* fsback = (FSBackend*)malloc(sizeof(FSBackend));
initDb(fsback,dbFile);
Tcl_Filesystem tfs;
tfs.typeName="Db Fs";
tfs.structureLength = sizeof(Tcl_Filesystem);
tfs.version = TCL_FILESYSTEM_VERSION_1;
tfs.pathInFilesystemProc = inFsProc;
/*...*/
Tcl_FSRegister((void*),tfs);
}
int inFsProc(Tcl_Obj* pathPtr,ClientData* cd)
{
/* How do I get my FSBackend struct here */
FSBackend* bk = /* ? */
int len;
const char* searchPath = Tcl_GetStringFromObj(pathPtr,&len);
char* foundPath = findFileInDb(searchPath,bk);
if (foundPath == 0) {
return -1;
}
cd = buildInternalRep(foundPath,bk);
return TCL_OK;
}
/**
...
*/
int main()
{
createFS("db1.db");
createFS("db2.db");
}
How do I, in inFsProc get back the struct I passed into Tcl_FSRegister?
The Tcl_FSData function says it can get it but I would then need to get a Tcl_Filesystem pointer
That's a weird one. The clientData handle there is not used to specify a mount point, but rather a separate capability of the filesystem type. Tcl's internal use of Tcl_FSRegister doesn't use it at all. The code which is as close as anything to a canonical use of it is the tclvfs package.
https://github.com/tcl-mirror/tclvfs/blob/master/generic/vfs.c#L385 shows us the use:
static void
Vfs_RegisterWithInterp(interp)
Tcl_Interp *interp;
{
ClientData vfsAlreadyRegistered;
/*
* We need to know if the interpreter is deleted, so we can
* remove all interp-specific mounts.
*/
Tcl_SetAssocData(interp, "vfs::inUse", (Tcl_InterpDeleteProc*)
Vfs_UnregisterWithInterp, (ClientData) 1);
/*
* Perform one-off registering of our filesystem if that
* has not happened before.
*/
vfsAlreadyRegistered = Tcl_FSData(&vfsFilesystem);
if (vfsAlreadyRegistered == NULL) {
Tcl_FSRegister((ClientData)1, &vfsFilesystem);
Tcl_CreateExitHandler(VfsExitProc, (ClientData)NULL);
Tcl_CreateThreadExitHandler(VfsThreadExitProc, NULL);
}
}
As you can see, the clientData there is really just being used as a marker so the code knows whether to do one-time initialisation.
To discover what the mount mapping is, you'll need to keep internal structures. You're strongly recommended to make the Tcl_Filesystem structure instance itself be global (or rather static at file scope) in your code.

Segmentation fault 11 in following code. How to avoid overflow?

void main(int argc, char* argv[]) {
char* hostname = (char*)malloc(sizeof(char)*1024);
hostname = getClientHostName("122.205.26.34");
printf("%s\n", hostname);
free(hostname);
}
char* getClientHostName(char* client_ip) {
char hostnames[5][2];
hostnames[0][0] = "122.205.26.34";
hostnames[0][1] = "aaaaa";
hostnames[1][0] = "120.205.36.30";
hostnames[1][1] = "bbbbb";
hostnames[2][0] = "120.205.16.36";
hostnames[2][1] = "ccccc";
hostnames[3][0] = "149.205.36.46";
hostnames[3][1] = "dddddd";
hostnames[4][0] = "169.205.36.33";
hostnames[4][1] = "eeeeee";
for(int i = 0; i<5; i++) {
if(!strcmp(hostnames[i][0], client_ip))
return (char*)hostnames[i][1];
}
return NULL;
}
Beginner in C.
I am not sure if there would be a better way to implement what I am trying to implement. The code is self-explanatory. Is there any way that I can predefine the size of hostname, using some general size of IP addresses, to avoid seg fault? Is there a even better way where I don't have to hardcode the size?
After fixing the compiler errors and warnings you get:
const char* getClientHostName(const char* client_ip) {
const char * hostnames[5][2];
hostnames[0][0] = "122.205.26.34";
hostnames[0][1] = "aaaaa";
hostnames[1][0] = "120.205.36.30";
hostnames[1][1] = "bbbbb";
hostnames[2][0] = "120.205.16.36";
hostnames[2][1] = "ccccc";
hostnames[3][0] = "149.205.36.46";
hostnames[3][1] = "dddddd";
hostnames[4][0] = "169.205.36.33";
hostnames[4][1] = "eeeeee";
for(int i = 0; i<5; i++) {
if(!strcmp(hostnames[i][0], client_ip))
return hostnames[i][1];
}
return NULL;
}
int main(int argc, char* argv[]) {
const char * hostname = getClientHostName("128.205.36.34");
printf("%s\n", hostname);
}
Is there a even better way where I don't have to hardcode the size?
Take the habit to compile with all warnings and debug info: gcc -Wall -Wextra -g with GCC. Improve the code to get no warnings at all.
If you want to get genuine IP addresses, this is operating system specific (since standard C11 don't know about IP addresses; check by reading n1570). On Linux you would use name service routines such as getaddrinfo(3) & getnameinfo(3) or the obsolete gethostbyname(3).
If this is just an exercise without actual relationship to TCP/IP sockets (see tcp(7), ip(7), socket(7)) you could store the table in some global array:
struct myipentry_st {
const char* myip_hostname;
const char* myip_address;
};
then define a global array containing them, with the convention of terminating it by some {NULL, NULL} entry:
const struct myipentry_st mytable[] = {
{"aaaaa", "122.205.26.34"},
{"bbbb", "120.205.36.30"},
/// etc
{NULL, NULL} // end marker
};
You'll better have a global or static variable (not an automatic one sitting on the call stack) because you don't want to fill it on every call to your getClientHostName.
Then your lookup routine (inefficient, since in linear time) would be:
const char* getClientHostName(char* client_ip) {
for (const struct myipentry_st* ent = mytable;
ent->myip_hostname != NULL;
ent++)
// the if below is the only statement of the body of `for` loop
if (!strcmp(ent->myip_address, client_ip))
return ent->myip_hostname;
// this happens after the `for` when nothing was found
return NULL;
}
You could even declare that table as a heap allocated pointer:
const struct myipentry_st**mytable;
then use calloc to allocate it and read its data from some text file.
Read the documentation of every standard or external function that you are using. Don't forget to check against failure (e.g. of calloc, like here). Avoid memory leaks by appropriate calls to free. Use the debugger gdb and valgrind. Beware of undefined behavior.
In the real world, you would have perhaps thousands of entries and you would perform the lookup many times (perhaps millions of times, e.g. once per every HTTP request in a web server or client). Then choose a better data structure (hash table or red-black tree perhaps). Read some Introduction to Algorithms.
Add * to type definition char * hostnames[5][2]. This must be array of pointers, not simple chars. Another necessary change is strcpy instead of = in strcpy( hostname, getClientHostName("122.205.26.34") );.
PS: Always try to compile with 0 compiler warnings, not only 0 errors!

c how to evaluate function pointer using function name

This is my snippet:
typedef void (*FUNCPT)(void);
void func1();
int main(){
FUNCPT fpt1;
char *s = "func1";
return 0;
}
I can evaluate fpt1 like this :
fpt1 = func1;
But there is some reason that I must use function name to evaluate function pointer, I expect to get same value by something like this:
fpt1 = (FUNCPT)s;
How can I achive this?
The only way to evaluate a function name to a function pointer (without referring to a fixed table of symbols vs. names in your own code) is using shared libraries and dlopen(), dlsym() and the likes in the Linux/Unix world and the appropriate equivalents in the Windows world.
Put the functions you want to resolve into a shared library
Open that shared library from your program using dlopen
Find the symbol by name using dlsym
Cast that returned address into a proper function pointer and call it
This is, however, more an OS than a C question. Without stating your platform, further help is not possible.
I don't think there is any portable way to do that. I think you need to write your own code for that. For instance a look-up table like:
#include <stdio.h>
void func1() {printf("func1\n");}
void func2() {printf("func2\n");}
void func3() {printf("func3\n");}
typedef void (*FUNCPT)(void);
typedef struct lookup
{
FUNCPT f;
char name[32];
} lookup;
lookup lookup_table[] = {
{func1, "func1"},
{func2, "func2"},
{func3, "func3"},
};
FUNCPT getFuncByName(char* str)
{
int i;
for (i=0; i < (sizeof(lookup_table)/sizeof(lookup)); ++i)
{
if (strcmp(str, lookup_table[i].name) == 0) return lookup_table[i].f;
}
return NULL;
}
int main(){
FUNCPT fpt = getFuncByName("func2");
if (fpt) fpt();
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.

Porting Unix to Windows- usage of pwd.h

I'm trying to compile libUnihan code with MinGW, but have run into a function which requires porting. The purpose of the function is to get a canonical path representation. It uses pwd.h (which is POSIX, and MinGW isn't) so it can account for the use of '~' to mean the home directory by retrieving a passwd struct, which contains pw_dir. I did find a little information here, and a port of realpath here, but I am still entirely at a loss as to how to deal with this. With MinGW, I still have a home directory represented by ~ and located at /home/nate, but since it isn't POSIX, I don't have pwd.h to help me find where this home directory is.
Q: How can I port the function below to work properly with MinGW?
/**
* Return the canonicalized absolute pathname.
*
* It works exactly the same with realpath(3), except this function can handle the path with ~,
* where realpath cannot.
*
* #param path The path to be resolved.
* #param resolved_path Buffer for holding the resolved_path.
* #return resolved path, NULL is the resolution is not sucessful.
*/
gchar*
truepath(const gchar *path, gchar *resolved_path){
gchar workingPath[PATH_MAX];
gchar fullPath[PATH_MAX];
gchar *result=NULL;
g_strlcpy(workingPath,path,PATH_MAX);
// printf("*** path=%s \n",path);
if ( workingPath[0] != '~' ){
result = realpath(workingPath, resolved_path);
}else{
gchar *firstSlash, *suffix, *homeDirStr;
struct passwd *pw;
// initialize variables
firstSlash = suffix = homeDirStr = NULL;
firstSlash = strchr(workingPath, DIRECTORY_SEPARATOR);
if (firstSlash == NULL)
suffix = "";
else
{
*firstSlash = 0; // so userName is null terminated
suffix = firstSlash + 1;
}
if (workingPath[1] == '\0')
pw = getpwuid( getuid() );
else
pw = getpwnam( &workingPath[1] );
if (pw != NULL)
homeDirStr = pw->pw_dir;
if (homeDirStr != NULL){
gint ret=g_sprintf(fullPath, "%s%c%s", homeDirStr, DIRECTORY_SEPARATOR, suffix);
if (ret>0){
result = realpath(fullPath, resolved_path);
}
}
}
return result;
}
The purpose is to implement ~[username]/ remapping logic. This sort of code makes sense in Linux/UNIX environments, but the most common use is just to refer to the user's own home directory.
For expediency, I'd just add support for the common case - ~/ - i.e. the current user, and not bother supporting the more general case - have it fail with an obvious error in that case.
The function to get the current user's home directory is SHGetFolderPath.
#include <windows.h>
char homeDirStr[MAX_PATH];
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, homeDirStr))) {
// Do something with the path
} else {
// Do something else
}
In the case of a failed lookup of the user, the code you pasted does not try to replace that string, but simply returns NULL, so you could emulate that.

Resources