Operating System - HP-UX
1834780 Members
2838 Online
110070 Solutions
New Discussion

some questions about a C program

 
SOLVED
Go to solution
curt larson_1
Honored Contributor

some questions about a C program

here is a short C program to return the boot_string from the running kernel.

1) being I'm not a C programmer, I'm looking for suggestions for improvements.

2)

a) how would i implement the ioctl statement if I had defined FILE *fp; instead of int fp; and used fopen and fclose. ie ioctl takes an int fildes.

b) how do you assign values using a pointer to a structure, ie how would you correctly do what I was trying to do in the comments.

3) my boot string is disk(8/0/19/0.6.0.0.0.0.0;0)/stand/vmunix. in C code how would i just get the "/stand/vmunix" portion.

4) can some whizbang perl wizard do this using perl? shouldn't be too hard. define a structure, assign vaules to the structure, open kmem, call ioctl, close kmem, parse the results, print out the kernel file name.


#include
#include
#include
#include

int main(void){
struct mioc_rksym abc, *rks = &abc;
char buf[1024];
int fp;

if (( fp = open("/dev/kmem",O_RDONLY)) == NULL ) {
printf("kmem could not be opened\n);
exit(1);
}
abc.mirk_modname=NULL;
abc.mirk_sysname="boot_string";
abc.mirk_buf=buf;
abc.mirk_buflen=1023;
/*
rks->mirk_modename=NULL;
rks->mirk_sysname="boot_string";
rks->mirk_buf=buf;
rks->mirk_buflen=1023;
*/

if ( ioctl( fp, MIOC_READKSYM, *rks) != 0 ) {
perror("ioctl");
return -1;
}
printf("%s"\n",rks->mirk_buf);
if (close(fp) == EOF)
printf("kmem could not be closed\n");
}

to compile

cc file.c -o ofile
17 REPLIES 17
James R. Ferguson
Acclaimed Contributor
Solution

Re: some questions about a C program

Hi Curt:

Why not(?):

# echo boot_string/S|adb /stand/vmunix /dev/mem

Regards!

...JRF...
Gregory Fruth
Esteemed Contributor

Re: some questions about a C program

2a) use fileno() on a file
pointer to get the
associated file descriptor:

FILE *fp;
fd = fileno(fp);

Then you can pass fd to
ioctl().

2b) AFAICT your commented
code should work, except
that you wrote "modename"
instead of "modname". You
also appear to be missing
some quotation marks here
and there, but I assume
those are transmission
errors.

3) Unless there's a more
precise way to get the
kernel file, perhaps you
could use strchr() to find
the ')' and do some string
ops on it:

c = strchr(mirk_buf, ')');
c = '\0';
c++;
printf("kernel is %s\n", c);

4) Unless there's a Perl
module that provides a nice high-level method for
doing what you want, the
equivalent Perl code won't
be any easier than the C
code. You'll still have to
do the ioctl() stuff, but
with the added complication
of having to use pack() and
unpack() to write and read
(respectively) the elements
of the struct.

HTH


Gregory Fruth
Esteemed Contributor

Re: some questions about a C program

Oops, part 3 should be more
like this:

char *c;
c = strchr(mirk_buf, ')');
c++;
printf("kernel is %s\n", c);
curt larson_1
Honored Contributor

Re: some questions about a C program

james,

because I want to know the name of the file that is the currently running kerenl.

your method only works if /stand/vmunix is the current kernel. And, if i already knew that /stand/vmunix was the kernel, I wouldn't need to do it at all.
curt larson_1
Honored Contributor

Re: some questions about a C program

Mr. Fruth,

thanks for all the feedback.

AFAICT? i'm not sure what that means.

2b) modename was a typo.

there is an extra " typo in one of the printfs but other then that this is it. it does compile. but if you think some are missing, I'd like to know.

if
struct mioc_rksym abc, *rks = &abc;
becomes just
struct mioc_rksym *rks;
take out all the abc stuff
and just do
rks->mirk_sysname="boot_string";
the program gets a bus error coredump at the assignment.

thanks again
curt larson_1
Honored Contributor

Re: some questions about a C program

Mr. Fruth,

added your

char *c;
c = strchr(mirk_buf, ')');
c++;
printf("kernel is %s\n", c);

code and it works very well.

I do get one of those pesky Integral value implictly converted to a pointer in assignment compiler warnings for the pointer arithmetic.

if it isn't too much trouble, how would I do this such that there isn't a warning message?

and i do hope you reply, as with 4 questions you should get 4x the points
A. Clay Stephenson
Acclaimed Contributor

Re: some questions about a C program

You had a few problems:

open() == NULL could be a good result because 0 is a valid file descrirptor.

Your pointer assignments should work but you really don't need a pointer - just pass the address of abc into the function. The hard coding of the size is VERY BAD FORM - that's what sizeof is for - so that buf and it's size always track each other.


fileno(fp) will return the file descriptor but real C programmers don't use *FILE's but instead use the file descriptors (at least for ioctl() stuff)

I spent about 3 minutes cleaning up your code and returning everything past the ')' - if found.

You might look at CPAN to see if theres a module but I wouldn't use Perl to a walking through kmem; it would be much to easy to accidently incude a print and write to /dev/kmem with possibly disasterous results.

If it ain't broke, I can fix that.
curt larson_1
Honored Contributor

Re: some questions about a C program

Thanks a lot for the rewrite Clay. that is a 50 point answer if there was one. 3 minutes, that is some fast typing.

would you happen to have a recomendation on the size to use for buf, ie what is the maximum length that the boot string can be?
A. Clay Stephenson
Acclaimed Contributor

Re: some questions about a C program

The correct answer is to replace your 1024 with MAXSYMNMLEN (which is acually 1024 undex 11.x but might change with a patch or OS upgrade) define found in sys/ksym.h.

The only other change (and this is nit-picky) is to add an #include so that close() has a prototype.
It will make lint a little happier.


If it ain't broke, I can fix that.
curt larson_1
Honored Contributor

Re: some questions about a C program

one last question. how would you print out the value of a kernel symbol that was a number? such as iticks_per_tick, which ends up in the first 4 elements of the array buf. buf is an character array. iticks_per_tick is a 32 bit integer.

what i did was
long * lg = (long *) buf;
printf("%d\n",*lg);

is there a better method of doing this?
A. Clay Stephenson
Acclaimed Contributor

Re: some questions about a C program

Well, your method works but it wouldn't work in all cases.

The ioctl call places the data into buf - which fortunately starts on a word boundary. You assignment method works fine in that case but if you had to move from starting at buf[1] to an int or a double then you might have problems. In that case, you would use memcpy.

Note the mirk_buf is really a void * - meaning that it can accept any type. Rigorously,
you should have

abc.mirk_buf = (void *) buf;
abc.mirk_buflen = sizeof(buf);
/* you don't really need to subtract 1 because the terminal '\0' is taken into account. */

For a long;
long tmp_long = 0L;
abc.mirk_buf = (void *) &tmp_long;
abc.mirk_buflen = sizeof(tmp_long);

Ideally, you should modify your code to accept command line args which identify the desired variable and it's type and then you have a flexible solution with a switch{ } to handle the various variable types.


If it ain't broke, I can fix that.
A. Clay Stephenson
Acclaimed Contributor

Re: some questions about a C program

Well, your method works but it wouldn't work in all cases.

The ioctl call places the data into buf - which fortunately starts on a word boundary. You assignment method works fine in that case but if you had to move from starting at buf[1] to an int or a double then you might have problems. In that case, you would use memcpy.

Note the mirk_buf is really a void * - meaning that it can accept any type. Rigorously,
you should have

abc.mirk_buf = (void *) buf;
abc.mirk_buflen = sizeof(buf);
/* you don't really need to subtract 1 because the terminal '\0' is taken into account. */

For a long;
long tmp_long = 0L;
abc.mirk_buf = (void *) &tmp_long;
abc.mirk_buflen = sizeof(tmp_long);

Ideally, you should modify your code to accept command line args which identify the desired variable and it's type and then you have a flexible solution with a switch{ } to handle the various variable types.


If it ain't broke, I can fix that.
A. Clay Stephenson
Acclaimed Contributor

Re: some questions about a C program

Well, your method works but it wouldn't work in all cases.

The ioctl call places the data into buf - which fortunately starts on a word boundary. You assignment method works fine in that case but if you had to move from starting at buf[1] to an int or a double then you might have problems. In that case, you would use memcpy.

Note the mirk_buf is really a void * - meaning that it can accept any type. Rigorously,
you should have

abc.mirk_buf = (void *) buf;
abc.mirk_buflen = sizeof(buf);
/* you don't really need to subtract 1 because the terminal '\0' is taken into account. */

For a long;
long tmp_long = 0L;
abc.mirk_buf = (void *) &tmp_long;
abc.mirk_buflen = sizeof(tmp_long);

Ideally, you should modify your code to accept command line args which identify the desired variable and it's type and then you have a flexible solution with a switch{ } to handle the various variable types.


If it ain't broke, I can fix that.
Gregory Fruth
Esteemed Contributor

Re: some questions about a C program

AFAICT = As Far As I Can Tell

2b) The first printf() is
missing a ", while the second
printf() has an extra one:

printf("kmem could not be opened\n);

printf("%s"\n",rks->mirk_buf);

Sounds like you figured out
how to handle the buffer
pointers & such.

As for the "integral value
converted to pointer" error,
you need to #include
to get the proto
for strchr(). The error
occurs because in the absence
of a prototype the compiler
assumes functions return
an int. So in the statement
c = strchr(...) the lhs is
a pointer while the rhs is
(incorrectly assumed to be)
an int, resulting in the
warning.

HTH (Hope That Helps)
curt larson_1
Honored Contributor

Re: some questions about a C program

Thanks very much for all the assistance fellows. I certainly appreciate it. attached is the lastest version.

one more question though,
for my kernel maxdsiz is 0X10000000

doing a echo "maxdsiz/X" | adb ... returns
10000

kmtune returns the appropriate value, but how would i get the value using adb?

thanks alot again
curt
curt larson_1
Honored Contributor

Re: some questions about a C program

noticed a couple of mistakes in the previous post. here is corrected version
James R. Ferguson
Acclaimed Contributor

Re: some questions about a C program

Hi Curt:

You asked, '...one more question though, for my kernel maxdsiz is 0X10000000 [but] doing a echo "maxdsiz/X" | adb " ... returns
10000' ...

That is correct. The 'maxdsize' value returned is in *pages*. In your case the PAGE_SIZE is undoubtedly 4096, although you can verify this by doing:

# getconf PAGE_SIZE

...4096 decimal is 0x1000 so:

...'adb' returned: 0x10000 pages

...or: 0x10000 * 0x1000 = 0x10000000

...as reported by 'kmtune', or in decimal: 268435456

Regards!

...JRF...