how to Find the Mount Path of Pendrive in better way? - c

I have a requirement like . My Embedded system consist of program which on start up looks for a pendrive and specific directory in pendrive. if the directories are found its considered as bootable device.
Consider Below code :
uint8 Check_BB_rootfs_Availability()
{
uint8 b_flag = 0x00;
dw_PkgAvailFlag |= BB_PKG_AVAIL_MASK;
if(!(system("ls /media1/sda/UPGRADE_FILES/BB/")))
{
path_argv[0] = "/media1/sda/UPGRADE_FILES/BB/rootfs.ubifs";
}
else if(!(system("ls /media1/sda1/UPGRADE_FILES/BB/")))
{
path_argv[0] = "/media1/sda/UPGRADE_FILES/BB/rootfs.ubifs";
}
else if(!(system("ls /media2/sda/UPGRADE_FILES/BB/")))
{
path_argv[0] = "/media2/sda/UPGRADE_FILES/BB/rootfs.ubifs";
}
else if(!(system("ls /media2/sda1/UPGRADE_FILES/BB/")))
{
path_argv[0] = "/media2/sda1/UPGRADE_FILES/BB/rootfs.ubifs";
}
else if(!(system("ls /media/sda/UPGRADE_FILES/BB/")))
{
path_argv[0] = "/media/sda/UPGRADE_FILES/BB/rootfs.ubifs";
}
else if(!(system("ls /media/sda1/UPGRADE_FILES/BB/")))
{
path_argv[0] = "/media/sda1/UPGRADE_FILES/BB/rootfs.ubifs";
}
else
{
/* Normal Boot */
dw_PkgAvailFlag &= ~(BB_PKG_AVAIL_MASK);
b_flag = 0x01;
}
return b_flag;
}
If rootfs is available . I call a script which does the upgrading .
Can this be done in some better way instead of using if..else condition and the systemcall.
Also I am facing another issue is when i am using system call i.e i cannot pass the char * path_argv[0] as an argument to system call. again i have to do is this
system("/media/sda1/UPGRADE_FILES/BB/UPGRADEBB_File.sh '/media/sda1/UPGRADE_FILES/BB/rootfs.ubifs'");
can some way i can pass the pointer without using the execv call as i dont want to create new process.

You might like to have a look at the stat() system call. It allows you to test for the existance of a certain file or directory.
You can use sprintf() to "print" into a "string".
char cmd[1024] = ""; /* Make sure this buffer is large enough. */
sprintf(cmd, "/media/sda1/UPGRADE_FILES/BB/UPGRADEBB_File.sh '%s'", path_argv[0]);
int result = system(cmd);

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.

Use of goto in Linux kernel code makes no sense

I was going through the Linux source code and here I stumbled over this function:
static int check_free_space(struct bsd_acct_struct *acct)
{
struct kstatfs sbuf;
if (time_is_after_jiffies(acct->needcheck))
goto out;
/* May block */
if (vfs_statfs(&acct->file->f_path, &sbuf))
goto out;
if (acct->active) {
u64 suspend = sbuf.f_blocks * SUSPEND;
do_div(suspend, 100);
if (sbuf.f_bavail <= suspend) {
acct->active = 0;
pr_info("Process accounting paused\n");
}
} else {
u64 resume = sbuf.f_blocks * RESUME;
do_div(resume, 100);
if (sbuf.f_bavail >= resume) {
acct->active = 1;
pr_info("Process accounting resumed\n");
}
}
acct->needcheck = jiffies + ACCT_TIMEOUT*HZ;
out:
return acct->active;
}
I can't find much sense in Marco's use of goto, especially since it leads to a return statement. Why wasn't the function re-written like this:
static int check_free_space(struct bsd_acct_struct * acct) {
struct kstatfs sbuf;
if (time_is_after_jiffies(acct->needcheck) ||
vfs_statfs( &acct->file->f_path, & sbuf)) {
//latter may block
return acct->active;
}
if (acct->active) {
u64 suspend = sbuf.f_blocks * SUSPEND;
do_div(suspend, 100);
if (sbuf.f_bavail <= suspend) {
acct->active = 0;
pr_info("Process accounting paused\n");
}
} else {
u64 resume = sbuf.f_blocks * RESUME;
do_div(resume, 100);
if (sbuf.f_bavail >= resume) {
acct->active = 1;
pr_info("Process accounting resumed\n");
}
}
acct->needcheck = jiffies + ACCT_TIMEOUT * HZ;
}
I've been taught that goto could indeed be useful if used to break out of a nested loop or for memory cleanup. Neither of this is a case here, so why did Marco go for the gotos? There must be some kind of valid reason, right?
Why wasn't the function re-written like this
The function that you just wrote is invalid. More precisely, if this block is not entered:
if (time_is_after_jiffies(acct->needcheck) ||
vfs_statfs( &acct->file->f_path, & sbuf)) {
vfs_statfs( &acct->file->f_path, & sbuf)) {
//latter may block
return acct->active;
}
Then the function will not be able to do a valid return anywhere else. The code will not even compile.
The purpose of the goto in that particular function is to execute an early return without the need of duplicating the return acct->active; line. This is a pretty common pattern which saves duplicated lines of code and sometimes also reduces the size of the resulting executable.
It's the "single return" principle. Some programmers think it should be obeyed at all times.
The function would work exactly the same if you replaced goto out; with return acct->active; However, let's say you want to do this:
out:
printf("Exiting function check_free_space()\n");
return acct->active;
That becomes a lot easier.
Here is a question about single return: Should a function have only one return statement?

How to modify an existing YAML node in C?

I am not C programmer but have recently taking interest in it. I am trying to modify a node of a YAML file using the C libyaml library. When I try to modify the node from an event scalar data the compiler doesn't complain but I get segmentation fault errors.
while (!done)
{
/* Get the next token. */
if (!yaml_parser_parse(&parser, &event))
goto parser_error;
//yaml_parser_scan(&parser, &token);
/* Check if this is the stream end. */
if(beginServerNodes && event.type == 8) {
beginServerNodes = 0;
}
if (event.type == YAML_SCALAR_EVENT) {
if(beginServerNodes == 1) {
//I WANT TO MODIFY THIS VALUE
printf("%s\n", event.data.scalar.value);
}
if(strcmp("servers",event.data.scalar.value) == 0) {
beginServerNodes = 1;
}
}
if (event.type == YAML_STREAM_END_EVENT) {
done = 1;
}
/* Emit the token. */
if (!yaml_emitter_emit(&emitter, &event))
goto emitter_error;
}
So while in that loop when I attempt to modify the following value
event.data.scalar.value
It must be of type yaml_char_t
yaml_char_t *newHost = "10.132.16.48:6379:1 redis-001";
event.data.scalar.value = newHost;
event.data.scalar.length = sizeof(newHost);
The compiler doesn't complain and the code run by dies with segementation fault. If have seen the examples in the libyaml test directories but nothing is intuitive as far as simply editing a node, at least not to a C newb like myself.
Libyaml expect that the values of each scalar can be removed via free(). So you need to initialize this value with malloc()ed memory:
const char* newHost = "10.132.16.48:6379:1 redis-001";
event.data.scalar.value = (yaml_char_t*)strdup(newHost);
event.data.scalar.length = strlen(newHost);

Pointers and String manipulation

I'm writing a function/method in C that is supposed to do the following:
/** * Recieves the list of arguments and copies to conffile the name
of * the configuration file. * Returns 1 if the default file name
was used or 2 if * the parameter -f existed and therefor the
specified name was used. Returns 0 if there is a -f * parameter
but is invalid. (last argument)
*/
Basically one of these two option will be "asked" by the program:
1- controller -f FCFS|LOOK
2- controller FCFS|LOOK
If the second is asked, we enter the case of using the default name.
int get_conf_name(char* argv[], char* conffile) {
// Searches for -f
s = strstr(*argv, "-f");
if(s != NULL){
if(//its valid){
strcpy(conffile, //the name of the file which comes after -f
return 2
}
else return 0
}
else{
strcpy(confile, "config.vss")
return 1
}
}
The problem here is how do I get the word after -f and copy it to confile? And, can I access argv the same way I access conffile, since one of them is an array?
I thought of using a for loop and a strlen, but that would be a lot of unecessary work for the computer wouldn't it?
I think the assignment expects you to go through the individual arguments one by one, comparing them to "-f".
If you see no -f, you know that the default file needs to be used
If you see the flag in the final position, you know that the -f is invalid
If you see the flag in the position k, then the file name will be in argv[k+1]
The skeleton of your program should look like this:
bool foundFlag = false;
for (int i = 1 ; i < argc ; i++) {
if (strcmp(argv[i], "-f") == 0) {
if (i == argc-1) {
// Error
} else {
// argv[i+1] is the file name;
}
foundFlag = true;
break;
}
}
if (!foundFlag) {
// Default name is used
}

How to get mounted drive's volume name in linux using C?

I'm currently working on program, which must display information about mounted flash drive. I want to display full space, free space, file system type and volume name. But problem is that, i can't find any API through which i can get volume name(volume label). Is there any api to do this?
p.s. full space, free space and file system type i'm getting via statfs function
Assuming that you work on a recent desktop-like distribution (Fedora, Ubuntu, etc.), you have HAL daemon running and a D-Bus session.
Within org.freedesktop.UDisks namespace you can find the object that represents this drive (say org/freedekstop/UDisks/devices/sdb/. It implements org.freedesktop.UDisks.interface. This interface has all the properties that you can dream of, including UUID (IdUuid), FAT label (IdLabel), all the details about filesystem, SMART status (if the drive supports that) etc. etc.
How to use D-Bus API in C is a topic for another question. I assume that's been already discussed in detail -- just search [dbus] and [c] tags.
Flash drives are generally FAT32, which means the "name" that you're looking for is probably the FAT drive label. The most common linux command to retrieve that information is mlabel from the mtools package.
The command looks like this:
[root#localhost]$ mlabel -i /dev/sde1 -s ::
Volume label is USB-DISK
This program works by reading the raw FAT header of the filesystem and retrieving the label from that data. You can look at the source code for the applciation to see how you can replicate the parsing of FAT data in your own application... or you can simply execute run the mlabel binary and read the result into your program. The latter sounds simpler to me.
To call the methods:
kernResult = self->FindEjectableCDMedia(&mediaIterator);
if (KERN_SUCCESS != kernResult) {
printf("FindEjectableCDMedia returned 0x%08x\n", kernResult);
}
kernResult = self->GetPath(mediaIterator, bsdPath, sizeof(bsdPath));
if (KERN_SUCCESS != kernResult) {
printf("GetPath returned 0x%08x\n", kernResult);
}
and the methods:
// Returns an iterator across all DVD media (class IODVDMedia). Caller is responsible for releasing
// the iterator when iteration is complete.
kern_return_t ScanPstEs::FindEjectableCDMedia(io_iterator_t *mediaIterator)
{
kern_return_t kernResult;
CFMutableDictionaryRef classesToMatch;
// CD media are instances of class kIODVDMediaTypeROM
classesToMatch = IOServiceMatching(kIODVDMediaClass);
if (classesToMatch == NULL) {
printf("IOServiceMatching returned a NULL dictionary.\n");
} else {
CFDictionarySetValue(classesToMatch, CFSTR(kIODVDMediaClass), kCFBooleanTrue);
}
kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, mediaIterator);
return kernResult;
}
// Given an iterator across a set of CD media, return the BSD path to the
// next one. If no CD media was found the path name is set to an empty string.
kern_return_t GetPath(io_iterator_t mediaIterator, char *Path, CFIndex maxPathSize)
{
io_object_t nextMedia;
kern_return_t kernResult = KERN_FAILURE;
DADiskRef disk = NULL;
DASessionRef session = NULL;
CFDictionaryRef props = NULL;
char * bsdPath = '\0';
*Path = '\0';
nextMedia = IOIteratorNext(mediaIterator);
if (nextMedia) {
CFTypeRef bsdPathAsCFString;
bsdPathAsCFString = IORegistryEntryCreateCFProperty(nextMedia,CFSTR(kIOBSDNameKey),kCFAllocatorDefault,0);
if (bsdPathAsCFString) {
//strlcpy(bsdPath, _PATH_DEV, maxPathSize);
// Add "r" before the BSD node name from the I/O Registry to specify the raw disk
// node. The raw disk nodes receive I/O requests directly and do not go through
// the buffer cache.
//strlcat(bsdPath, "r", maxPathSize);
size_t devPathLength = strlen(bsdPath);
if (CFStringGetCString( (CFStringRef)bsdPathAsCFString , bsdPath + devPathLength,maxPathSize - devPathLength, kCFStringEncodingUTF8)) {
qDebug("BSD path: %s\n", bsdPath);
kernResult = KERN_SUCCESS;
}
session = DASessionCreate(kCFAllocatorDefault);
if(session == NULL) {
qDebug("Can't connect to DiskArb\n");
return -1;
}
disk = DADiskCreateFromBSDName(kCFAllocatorDefault, session, bsdPath);
if(disk == NULL) {
CFRelease(session);
qDebug( "Can't create DADisk for %s\n", bsdPath);
return -1;
}
props = DADiskCopyDescription(disk);
if(props == NULL) {
CFRelease(session);
CFRelease(disk);
qDebug("Can't get properties for %s\n",bsdPath);
return -1;
}
CFStringRef daName = (CFStringRef )CFDictionaryGetValue(props, kDADiskDescriptionVolumeNameKey);
CFStringGetCString(daName,Path,sizeof(Path),kCFStringEncodingUTF8);
if(daName) {
qDebug("%s",Path);
CFRetain(daName);
}
CFRelease(daName);
CFRelease(props);
CFRelease(disk);
CFRelease(session);
CFRelease(bsdPathAsCFString);
}
IOObjectRelease(nextMedia);
}
return kernResult;
}

Resources