WP Plugin with Alt-Ergo - unable to prove? - frama-c

I'm trying to test WP plugin with Alt-Ergo on a fairly complex function. Unfortunately, I am not able to figure out what's wrong with the "basic" behavior given below.
This behavior should be true because there is no other place tenumRMode is updated except the first conditional statement's else section.
The wierd thing is that if I comment some lines arbitrarily I always get "valid" from Alt-ergo.
Any comments?
/*# behavior basic:
# assumes fRrValue == 0;
# ensures tenumRMode == SS_A_MODE;
#
*/
[formal_verification]$ frama-c -wp -wp-rte -wp-bhv=basic foo.c -wp-out t -lib-entry -main foo -wp-model ref -wp-timeout=50 -wp-fct=foo -wp-out t
[kernel] preprocessing with "gcc -C -E -I. foo.c"
[wp] Running WP plugin...
[rte] annotating function foo
[wp] Collecting axiomatic usage
[wp] Collecting variable usage
[wp] 1 goal scheduled
[wp] [Alt-Ergo] Goal typed_ref_foo_basic_post : Unknown (Qed:20ms)
typedef unsigned char BOOL;
#define TRUE 1
#define FALSE 0
typedef unsigned char uint8;
typedef unsigned short int uint16;
typedef unsigned long uint32;
uint16 F_MIN_R = 15;
const uint8 RESP_STATE = 30;
typedef enum
{
RESP_MODE,
SS_A_MODE
}tenumMode;
tenumMode tenumRMode;
BOOL gbCaMStatus;
BOOL gbCaaStatus;
uint8 mnPb;
BOOL mbApLYRange;
BOOL mbApLRange;
float gfApYLineSlope;
float gfApYLineConst;
float gfApRLineSlope;
float gfApRLineConst;
float mfAp;
uint16 almC;
uint16 nApLYL = 0;
uint16 nApLRL = 0;
uint16 Ap_Y_L_Ui = 0;
uint16 Ap_R_L_Ui = 0;
float fCaValue=0.0;
float fRrValue = 0.0;
uint16 nCaLYL=0;
uint16 nCaLRL=0;
/*# behavior basic:
# assumes fRrValue == 0;
# ensures tenumRMode == SS_A_MODE;
#
*/
void foo()
{
float mfNewAp = 0;
BOOL bYAp = FALSE;
BOOL bRAp = FALSE;
BOOL bApAlmC = FALSE;
if (fRrValue != 0)
{
/* Some code here */
}
else
{
if (mnPb == 1)
{
mfAp = RESP_STATE;
mnPb = 2;
}
tenumRMode = SS_A_MODE;
}
if ( (mfAp >= F_MIN_R) &&
((gbCaMStatus == TRUE) && (gbCaaStatus == FALSE)) )
{
bApAlmC = TRUE;
almC = 1;
}
else
{
almC = 0;
}
if ( (bApAlmC == TRUE)
&& (mfAp < nApLYL)
&& (fCaValue >= nCaLYL) )
{
float fmultval = 0;
fmultval = gfApYLineSlope*fCaValue;
mfNewAp = fmultval + gfApYLineConst;
if (mfAp >= mfNewAp)
bYAp = TRUE;
else
bYAp = FALSE;
Ap_Y_L_Ui = (uint16)mfNewAp;
}
if ((bApAlmC == TRUE) && (fCaValue > (float)nCaLYL))
{
mfNewAp = ((gfApYLineSlope*fCaValue) + gfApYLineConst);
if (mfNewAp < (float)nApLYL);
Ap_Y_L_Ui = (uint16)mfNewAp;
}
else if ((bApAlmC == TRUE) && (fCaValue <= (float)nCaLYL))
Ap_Y_L_Ui = F_MIN_R;
if ( (bApAlmC == TRUE) && (fCaValue >= nCaLRL) )
{
float fmultval = 0;
fmultval = gfApRLineSlope*fCaValue;
mfNewAp = fmultval + gfApRLineConst;
if (mfAp >= mfNewAp)
bRAp = TRUE;
else
bRAp = FALSE;
Ap_R_L_Ui = (uint16)mfNewAp;
}
else if ( (bApAlmC == TRUE) && (fCaValue < nCaLRL) )
Ap_R_L_Ui = F_MIN_R;
if ( (mfAp >= nApLYL)
|| ((bApAlmC == TRUE) && (fCaValue < nCaLYL))
|| ((bYAp == TRUE)
&& (gbCaMStatus == TRUE) && (gbCaaStatus == FALSE) ) )
{
mbApLYRange = TRUE;
}
else
mbApLYRange = FALSE;
if ( (mfAp >= nApLRL)
|| ((bApAlmC == TRUE) && (fCaValue < nCaLRL))
|| ((bRAp == TRUE)
&& (gbCaMStatus == TRUE) && (gbCaaStatus == FALSE) ) )
{
/* Some code here */
}
}

Which versions of Alt-ergo and Frama-C are you using ? I tried your example using Frama-C Oxygen-20120901 and Alt-Ergo version 0.95.2 (installed via OPAM) and I got:
$ frama-c -wp -wp-rte -lib-entry -main foo foo.c -wp-bhv=basic
[kernel] preprocessing with "gcc -C -E -I. foo.c"
[wp] Running WP plugin...
[wp] Collecting axiomatic usage
foo.c:51:[wp] warning: [get_strategies] no behaviors found
foo.c:51:[wp] warning: [get_strategies] no behaviors found
[rte] annotating function foo
[wp] 1 goal scheduled
[wp] [Alt-Ergo] Goal store_foo_basic_post : Unknown
When I tried directly Alt-Ergo (v. 0.95.2), I got:
$ alt-ergo store_foo_basic_post_po_ergo.why
File "store_foo_basic_post_po_ergo.why", line 1220, characters 22-24:syntax error
The VC is proved after fixing the syntax erros by hand. I think Alt-Ergo v. >= 0.95 is not compatible with Frama-C Oxygen. BTW, I don't know way OPAM had'nt installed the latest version of Frama-C on my computer (i.e. Fluorine-20130601)
-- Regards

Related

RISC-V undefined reference to `memcpy'

I am using RISC-V 32E toolchain to compile some standalone CPP code. I got errors below.
/opt/riscv32i/bin/riscv32-unknown-elf-g++ -Os -ffreestanding -o firmware/firmware.elf \
-Wl,-Bstatic,-T,firmware/sections.lds,-Map,firmware/firmware.map,--strip-debug \
firmware/start.o firmware/print.o firmware/stream.o firmware/main.o firmware/accel.o firmware/data_redir_m.o -lgcc -fno-threadsafe-statics -nostdlib
/opt/riscv32i/lib/gcc/riscv32-unknown-elf/8.2.0/../../../../riscv32-unknown-elf/bin/ld: firmware/data_redir_m.o: in function `.L31':
data_redir_m.cpp:(.text+0x442): undefined reference to `memcpy'
collect2: error: ld returned 1 exit status
Makefile:46: recipe for target 'firmware/firmware.elf' failed
make: *** [firmware/firmware.elf] Error 1
I want to keep the hex file as small as possible, so my preference is to not use -lstdc++ library. What confused me a lot is why it still complains about such errors even if I manually add the memcpy() function definition in data_redir_m.cpp file.
#include "typedefs.h"
void * memcpy ( void * destination, const void * source, int num ){
int i=0;
*((int*)destination) = *((int*)source);
}
static int check_clockwise( Triangle_2D triangle_2d )
{
int cw;
cw = (triangle_2d.x2 - triangle_2d.x0) * (triangle_2d.y1 - triangle_2d.y0)
- (triangle_2d.y2 - triangle_2d.y0) * (triangle_2d.x1 - triangle_2d.x0);
return cw;
}
// swap (x0, y0) (x1, y1) of a Triangle_2D
static void clockwise_vertices( Triangle_2D *triangle_2d )
{
bit8 tmp_x, tmp_y;
tmp_x = triangle_2d->x0;
tmp_y = triangle_2d->y0;
triangle_2d->x0 = triangle_2d->x1;
triangle_2d->y0 = triangle_2d->y1;
triangle_2d->x1 = tmp_x;
triangle_2d->y1 = tmp_y;
}
// find the min from 3 integers
static bit8 find_min( bit8 in0, bit8 in1, bit8 in2 )
{
if (in0 < in1)
{
if (in0 < in2)
return in0;
else
return in2;
}
else
{
if (in1 < in2)
return in1;
else
return in2;
}
}
// find the max from 3 integers
static bit8 find_max( bit8 in0, bit8 in1, bit8 in2 )
{
if (in0 > in1)
{
if (in0 > in2)
return in0;
else
return in2;
}
else
{
if (in1 > in2)
return in1;
else
return in2;
}
}
// project a 3D triangle to a 2D triangle
void projection(
bit32 input_lo,
bit32 input_mi,
bit32 input_hi,
Triangle_2D *triangle_2d
)
{
#pragma HLS INLINE off
Triangle_3D triangle_3d;
// Setting camera to (0,0,-1), the canvas at z=0 plane
// The 3D model lies in z>0 space
// The coordinate on canvas is proportional to the corresponding coordinate
// on space
bit2 angle = 0;
triangle_3d.x0 = bit8(input_lo( 7, 0));
triangle_3d.y0 = bit8(input_lo(15, 8));
triangle_3d.z0 = bit8(input_lo(23, 16));
triangle_3d.x1 = bit8(input_lo(31, 24));
triangle_3d.y1 = bit8(input_mi( 7, 0));
triangle_3d.z1 = bit8(input_mi(15, 8));
triangle_3d.x2 = bit8(input_mi(23, 16));
triangle_3d.y2 = bit8(input_mi(31, 24));
triangle_3d.z2 = bit8(input_hi( 7, 0));
if(angle == 0)
{
triangle_2d->x0 = triangle_3d.x0;
triangle_2d->y0 = triangle_3d.y0;
triangle_2d->x1 = triangle_3d.x1;
triangle_2d->y1 = triangle_3d.y1;
triangle_2d->x2 = triangle_3d.x2;
triangle_2d->y2 = triangle_3d.y2;
triangle_2d->z = triangle_3d.z0 / 3 + triangle_3d.z1 / 3 + triangle_3d.z2 / 3;
}
else if(angle == 1)
{
triangle_2d->x0 = triangle_3d.x0;
triangle_2d->y0 = triangle_3d.z0;
triangle_2d->x1 = triangle_3d.x1;
triangle_2d->y1 = triangle_3d.z1;
triangle_2d->x2 = triangle_3d.x2;
triangle_2d->y2 = triangle_3d.z2;
triangle_2d->z = triangle_3d.y0 / 3 + triangle_3d.y1 / 3 + triangle_3d.y2 / 3;
}
else if(angle == 2)
{
triangle_2d->x0 = triangle_3d.z0;
triangle_2d->y0 = triangle_3d.y0;
triangle_2d->x1 = triangle_3d.z1;
triangle_2d->y1 = triangle_3d.y1;
triangle_2d->x2 = triangle_3d.z2;
triangle_2d->y2 = triangle_3d.y2;
triangle_2d->z = triangle_3d.x0 / 3 + triangle_3d.x1 / 3 + triangle_3d.x2 / 3;
}
}
// calculate bounding box for a 2D triangle
void rasterization1 (
Triangle_2D triangle_2d,
hls::stream<ap_uint<32> > & Output_1,
hls::stream<ap_uint<32> > & Output_2
)
{
Triangle_2D triangle_2d_same;
bit8 max_min[5];
max_min[0]=0;
max_min[1]=0;
max_min[2]=0;
max_min[3]=0;
max_min[4]=0;
bit16 max_index[1];
max_index[0]=0;
bit32 tmp1, tmp2, tmp3, tmp4;
static int parity = 0;
#pragma HLS INLINE off
// clockwise the vertices of input 2d triangle
if ( check_clockwise( triangle_2d ) == 0 ){
tmp1(7,0) = 1;
tmp1(15, 8) = triangle_2d_same.x0;
tmp1(23,16) = triangle_2d_same.y0;
tmp1(31,24) = triangle_2d_same.x1;
tmp2(7,0) = triangle_2d_same.y1;
tmp2(15, 8) = triangle_2d_same.x2;
tmp2(23,16) = triangle_2d_same.y2;
tmp2(31,24) = triangle_2d_same.z;
tmp3(15,0) = max_index[0];
tmp3(23,16) = max_min[0];
tmp3(31,24) = max_min[1];
tmp4(7,0) = max_min[2];
tmp4(15, 8) = max_min[3];
tmp4(23,16) = max_min[4];
tmp4(31,24) = 0;
if(parity==0){
Output_1.write(tmp1);
Output_1.write(tmp2);
Output_1.write(tmp3);
Output_1.write(tmp4);
parity = 1;
}else{
Output_2.write(tmp1);
Output_2.write(tmp2);
Output_2.write(tmp3);
Output_2.write(tmp4);
parity = 0;
}
#ifdef PROFILE
data_redir_m_out_1+=4;
#endif
return;
}
if ( check_clockwise( triangle_2d ) < 0 )
clockwise_vertices( &triangle_2d );
// copy the same 2D triangle
triangle_2d_same.x0 = triangle_2d.x0;
triangle_2d_same.y0 = triangle_2d.y0;
triangle_2d_same.x1 = triangle_2d.x1;
triangle_2d_same.y1 = triangle_2d.y1;
triangle_2d_same.x2 = triangle_2d.x2;
triangle_2d_same.y2 = triangle_2d.y2;
triangle_2d_same.z = triangle_2d.z ;
// find the rectangle bounds of 2D triangles
max_min[0] = find_min( triangle_2d.x0, triangle_2d.x1, triangle_2d.x2 );
max_min[1] = find_max( triangle_2d.x0, triangle_2d.x1, triangle_2d.x2 );
max_min[2] = find_min( triangle_2d.y0, triangle_2d.y1, triangle_2d.y2 );
max_min[3] = find_max( triangle_2d.y0, triangle_2d.y1, triangle_2d.y2 );
max_min[4] = max_min[1] - max_min[0];
// calculate index for searching pixels
max_index[0] = (max_min[1] - max_min[0]) * (max_min[3] - max_min[2]);
tmp1(7,0) = 0;
tmp1(15,8) = triangle_2d_same.x0;
tmp1(23,16) = triangle_2d_same.y0;
tmp1(31,24) = triangle_2d_same.x1;
tmp2(7,0) = triangle_2d_same.y1;
tmp2(15,8) = triangle_2d_same.x2;
tmp2(23,16) = triangle_2d_same.y2;
tmp2(31,24) = triangle_2d_same.z;
tmp3(15,0) = max_index[0];
tmp3(23,16) = max_min[0];
tmp3(31,24) = max_min[1];
tmp4(7,0) = max_min[2];
tmp4(15,8) = max_min[3];
tmp4(23, 16) = max_min[4];
tmp4(31, 24) = 0;
if(parity==0){
Output_1.write(tmp1);
Output_1.write(tmp2);
Output_1.write(tmp3);
Output_1.write(tmp4);
parity = 1;
}else{
Output_2.write(tmp1);
Output_2.write(tmp2);
Output_2.write(tmp3);
Output_2.write(tmp4);
parity = 0;
}
return;
}
void data_redir_m (
hls::stream<ap_uint<32> > & Input_1,
hls::stream<ap_uint<32> > & Output_1,
hls::stream<ap_uint<32> > & Output_2
)
{
#pragma HLS INTERFACE ap_hs port=Input_1
#pragma HLS INTERFACE ap_hs port=Output_1
#pragma HLS INTERFACE ap_hs port=Output_2
bit32 input_lo;
bit32 input_mi;
bit32 input_hi;
bit128 input_tmp;
hls::stream<ap_uint<32> > Output_1_1;
hls::stream<ap_uint<32> > Output_2_2;
Triangle_2D triangle_2ds_1;
Triangle_2D triangle_2ds_2;
input_lo = Input_1.read();
input_mi = Input_1.read();
input_hi = Input_1.read();
#ifdef PROFILE
data_redir_m_in_1+=3;
#endif
projection (input_lo,input_mi,input_hi,&triangle_2ds_1);
rasterization1 (triangle_2ds_1, Output_1, Output_2);
}
If you want to build gcc for non-os environment, you need to build newlib in advance. And tell gcc where to find the libc, the way is to declare sysroot when configure the project.
You can use this script(ian910297/build-riscv-gnu-toolchain) to build riscv gnu toolchain. If you choose this method, be care of the directory name.
Otherwise, riscv official also provide similar script to build, like: riscv/riscv-gnu-toolchain)

Assertion on pointer to array

I have defined the following function which is well proved by frama-c:
//ensures array <= \result < array+length && *\result == element;
/*#
requires 0 < length;
requires \valid_read(array + (0 .. length-1));
assigns \nothing;
behavior in:
assumes \exists int off ; 0 <= off < length && array[off] == element;
ensures *\result == element;
behavior notin:
assumes \forall int off ; 0 <= off < length ==> array[off] != element;
ensures \result == 0;
disjoint behaviors;
complete behaviors;
*/
int* search(int* array, int length, int element){
int *tmp;
/*#
loop invariant 0 <= i <= length;
loop invariant \forall int j; 0 <= j < i ==> array[j] != element;
loop assigns i;
loop variant length-i;
*/
for(int i = 0; i < length; i++)
{
if(array[i] == element)
{
tmp = &array[i];
//# assert *tmp==element;
}
else
{
tmp = 0;
}
}
return tmp;
}
and I use it in the following main entry:
int main(){
int arr[5]={1,2,3,4,5};
int *p_arr;
p_arr = search(arr,5,4);
//# assert *p_arr==30;
return 0
}
I am wondering why frama-c give the assertion "//# assert *p_arr==30;" as true, I do not understand.
Thanks
Using the command line only, I saw some problems in your code:
tmp is missing in the loop assigns;
you need to:
either add a break in the then branch of the seach function
(then you would return the pointer on the first element that match)
or initialize tmp = 0 at the beginning of the function and remove the else branch in the loop (then you would return a pointer on the last occurrence).
I didn't try the GUI, but it seems strange that you say that your example is:
well proved by frama-c
I suggest that you use the command line to begin with.
Ok now I correct my code as follow:
//ensures array <= \result < array+length && *\result == element;
/*#
requires 0 < length;
requires \valid_read(array + (0 .. length-1));
assigns \nothing;
behavior in:
assumes \exists int off ; 0 <= off < length && array[off] == element;
ensures *\result == element;
behavior notin:
assumes \forall int off ; 0 <= off < length ==> array[off] != element;
ensures \result == 0;
disjoint behaviors;
complete behaviors;
*/
int* search(int* array, int length, int element){
/*#
loop invariant 0 <= i <= length;
loop invariant \forall int j; 0 <= j < i ==> array[j] != element;
loop assigns i;
loop variant length-i;
*/
for(int i = 0; i < length ; i++)
{
if(array[i] == element)
{
return &array[i];
}
}
return 0;
}
and add the following assertion:
int main()
{
int arr[5] = {1,2,3,4,5};
int *ptr;
ptr = search(arr,5,3);
//# assert *ptr==3;
}
then run: frama-c -wp -rte myfile.c and got the result:
[wp] Proved goals: 65 / 65
Qed: 35 (1.00ms-6ms-24ms)
Alt-Ergo: 30 (16ms-30ms-94ms) (132)
If I set another assertion :
int main()
{
int arr[5] = {1,2,3,4,5};
int *ptr;
ptr = search(arr,5,3);
//# assert *ptr==5;
}
Then I get the output:
[wp] [Alt-Ergo] Goal typed_main_assert_2 : Timeout (Qed:4ms) (10s)
[wp] Proved goals: 64 / 65
Qed: 35 (1.00ms-4ms-10ms)
Alt-Ergo: 29 (16ms-28ms-109ms) (132) (interrupted: 1)
So the assertion is "unknown" as we expected and if we run frama-c-gui the bullet is orange.
So that's working fine , take care about wrong axiomatic stuff !
Thank you Anne for your help.

Automated build and previously applied patches

How can I prevent aborted builds when a previously applied patch is detected without:
simply ignoring all failed patches
requiring user input
Patch itself is capable of identifying a previously applied patch. There's got to be a way to avoid the non-zero exit status on previously applied patches, right?
This doesn't work:
yes 'n' | patch -p<w/e> -i <w/e>
Because patch reads from /dev/tty (I'm guessing) instead of stdin. Even if it did read from stdin, it still gives an exit status of 1.
It seems like I'm missing something. I can't be the first to have run into this problem.
I think I may have just solved my problem.
diff --git a/src/common.h b/src/common.h
index 9e355fe..e1b1555 100644
--- a/src/common.h
+++ b/src/common.h
## -108,8 +108,10 ## XTERN bool force;
XTERN bool batch;
XTERN bool noreverse;
XTERN bool reverse;
+XTERN bool applied;
XTERN enum { DEFAULT_VERBOSITY, SILENT, VERBOSE } verbosity;
XTERN bool skip_rest_of_patch;
+XTERN bool applied_is_cause;
XTERN int strippath;
XTERN bool canonicalize;
XTERN int patch_get;
diff --git a/src/patch.c b/src/patch.c
index a60e631..3d375b3 100644
--- a/src/patch.c
+++ b/src/patch.c
## -613,7 +613,8 ## main (int argc, char **argv)
if (fstat (fileno (rejfp), &rejst) != 0 || fclose (rejfp) != 0)
write_fatal ();
rejfp = NULL;
- somefailed = true;
+ if (! somefailed && ! (applied && applied_is_cause))
+ somefailed = true;
say ("%d out of %d hunk%s %s", failed, hunk, "s" + (hunk == 1),
skip_rest_of_patch ? "ignored" : "FAILED");
if (outname && (! rejname || strcmp (rejname, "-") != 0)) {
## -629,7 +630,7 ## main (int argc, char **argv)
rej[len - 1] = '#';
simple_backup_suffix = s;
}
- if (! dry_run)
+ if (! dry_run && ! (applied && applied_is_cause))
{
say (" -- saving rejects to file %s\n", quotearg (rej));
if (rejname)
## -706,9 +707,10 ## reinitialize_almost_everything (void)
reverse = reverse_flag_specified;
skip_rest_of_patch = false;
+ applied_is_cause = false;
}
-static char const shortopts[] = "bB:cd:D:eEfF:g:i:l"
+static char const shortopts[] = "abB:cd:D:eEfF:g:i:l"
#if 0 && defined ENABLE_MERGE
"m"
#endif
## -716,6 +718,7 ## static char const shortopts[] = "bB:cd:D:eEfF:g:i:l"
static struct option const longopts[] =
{
+ {"applied", no_argument, NULL, 'a'},
{"backup", no_argument, NULL, 'b'},
{"prefix", required_argument, NULL, 'B'},
{"context", no_argument, NULL, 'c'},
## -777,6 +780,7 ## static char const *const option_help[] =
"",
" -N --forward Ignore patches that appear to be reversed or already applied.",
" -R --reverse Assume patches were created with old and new files swapped.",
+" -a --applied Ignore error and save no rejects on applied or reversed patch.",
"",
" -i PATCHFILE --input=PATCHFILE Read patch from PATCHFILE instead of stdin.",
"",
## -869,6 +873,9 ## get_some_switches (void)
while ((optc = getopt_long (Argc, Argv, shortopts, longopts, (int *) 0))
!= -1) {
switch (optc) {
+ case 'a':
+ applied = true;
+ break;
case 'b':
make_backups = true;
/* Special hack for backward compatibility with CVS 1.9.
diff --git a/src/util.c b/src/util.c
index ee88c13..432bc5c 100644
--- a/src/util.c
+++ b/src/util.c
## -1056,6 +1056,7 ## ok_to_reverse (char const *format, ...)
{
say (" Skipping patch.\n");
skip_rest_of_patch = true;
+ applied_is_cause = true;
}
else if (force)
{
## -1079,6 +1080,7 ## ok_to_reverse (char const *format, ...)
if (verbosity != SILENT)
say ("Skipping patch.\n");
skip_rest_of_patch = true;
+ applied_is_cause = true;
}
}
}

Convert a string from UART to hex value in c

I am working on pic controllers. I have a string "040F" which is sent to the controller through UART.
I want to convert this string to a hex representation such as 0x040F. I tried a code snippet but no success.
Can anyone please help me out.
If what you mean is to convert a hex string to binary, the below code can help. It may not be an optimized one and may be other simpler solutions are available in the internet and can be even buggy. But it will give you some idea, I hope.
#include<stdio.h>
#include<string.h>
#define MAX_STR_LEN 16
int hex_char_to_bin(char ch)
{
if(ch >= '0' && ch <= '9')
{
return (ch - '0');
}
else if(ch >= 'a' && ch <= 'f')
{
return (10 + ch - 'a');
}
else if(ch >= 'A' && ch <= 'F')
{
return (10 + ch - 'A');
}
return -1;
}
int hex_str_to_bin(const char *hex_str, int *result)
{
int str_len, i;
int bin_val = 0;
str_len = strnlen(hex_str, MAX_STR_LEN);
for (i = 0; i < str_len; i++)
{
int val = hex_char_to_bin(*hex_str++);
if (val == -1)
return -1;
bin_val = (bin_val<<4) + val;
}
*result = bin_val;
return 0;
}
int main()
{
char str[] = "043f";
int hex;
if(!hex_str_to_bin(str, &hex))
printf("%x\n",hex);
else
printf("Invalid hex charecters in string\n");
return 0;
}

File modification time (seconds) on Unix

On Unix, is there a command to display a file's modification time, precise to the second?
On Linux this is easily done with a "stat -c %y", which returns something like 2009-11-27 11:36:06.000000000 +0100. I found no equivalent on Unix.
I found this:
ls --time-style='+%d-%m-%Y %H:%M:%S' -l
Which exports something like this:
root:~# ls --time-style='+%d-%m-%Y %H:%M:%S' -l
total 0
-rw-r--r-- 1 root root 0 16-04-2015 23:14:02 other-file.txt
-rw-r--r-- 1 root root 0 16-04-2015 23:13:58 test.txt
According to the man page on my Mac (which has the BSD standard version of stat) you can get the epoch time version of the modification in seconds with:
stat -f %m /etc/passwd
Or if you want to print that out in hours:mins:secs you can do this:
perl -e "print scalar(localtime(`stat -f %m /etc/passwd`))"
The following gives you last modified time in seconds since Epoch:
stat -c%Y <file>
The find command is a good source for all kinds of file information, including modification time to the second:
find /etc/passwd -maxdepth 0 -printf "%TY/%Tm/%Td %TH:%TM:%.2TS\n"
2011/11/21 13:41:36
The first argument can be a file. The maxdepth prevents searching if a directory name is given. The %T instructs it to print last modification time.
Some systems interpret %TS as a floating point seconds (e.g. 36.8342610). If you want fractional seconds use "%TS" instead of "%.2TS", but you may not see fractional seconds on every system.
For anyone facing the same issue, I found no solution (on HP-UX 11i anyway).
Ended up coding a personalized "ls -lh" for my needs. It's not that hard..
Prints something like :
- 664 rw-/rw-/r-- 1L expertNoob adm 8.37 kB 2010.08.24 12:11:15 findf1.c
d 775 rwx/rwx/r-x 2L expertNoob adm 96 B 2010.08.24 15:17:37 tmp/
- 775 rwx/rwx/r-x 1L expertNoob adm 16 kB 2010.08.24 12:35:30 findf1
- 775 rwx/rwx/r-x 1L expertNoob adm 24 kB 2010.09.14 19:45:20 dir_info
- 444 r--/r--/r-- 1L expertNoob adm 9.01 kB 2010.09.01 11:23:41 getopt.c
- 664 rw-/rw-/r-- 1L expertNoob adm 6.86 kB 2010.09.01 11:24:47 getopt.o
- 664 rw-/rw-/r-- 1L expertNoob adm 6.93 kB 2010.09.14 19:37:44 findf1.o
l 775 rwx/rwx/r-x 1L expertNoob adm 6 B 2010.10.06 17:09:01 test1 -> test.c
- 664 rw-/rw-/r-- 1L expertNoob adm 534 B 2009.03.26 15:34:23 > test.c
d 755 rwx/r-x/r-x 25L expertNoob adm 8 kB 2009.05.20 15:36:23 zip30/
Here it is :
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <locale.h>
#include <langinfo.h>
#include <stdio.h>
//#include <stdint.h>
#include <limits.h> // PATH_MAX
#include <stdarg.h>
#include "getopt.h"
static short START_VSNBUFF=16;
// This is bformat from Better String library (bstrlib), customized
int strformat (char ** str, const char * fmt, ...) {
va_list arglist;
char * buff;
int n, r;
/* Since the length is not determinable beforehand, a search is
performed using the truncating "vsnprintf" call (to avoid buffer
overflows) on increasing potential sizes for the output result. */
if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF;
if ( NULL == ( buff = (char *) malloc((n + 2)*sizeof(char)) ) ) {
n = 1;
if ( NULL == ( buff = (char *) malloc((n + 2)*sizeof(char)) ) ) {
fprintf( stderr, "strformat: not enough memory to format string\n" );
return -1;
}
}
for (;;) {
va_start (arglist, fmt);
r = vsnprintf (buff, n + 1, fmt, arglist); // n+1 chars: buff[0]..buff[n], n chars from arglist: buff[n]='\0'
va_end (arglist);
buff[n] = (unsigned char) '\0'; // doesn't hurt, especially strlen!
if ( strlen(buff) < n ) break;
if (r > n) n = r; else n += n;
if ( NULL == ( buff = (char *) realloc( buff, (n + 2)*sizeof(char) ) ) ) {
free(buff);
fprintf( stderr, "strformat: not enough memory to format string\n" );
return -1;
}
}
if( NULL != *str ) free(*str);
*str = buff;
return 0;
}
int printFSObjectInfo( const char * path, const char * name ) {
struct stat statbuf;
struct passwd *pwd;
struct group *grp;
struct tm *tm;
char datestring[256];
char *type = "? ";
char *fbuf = NULL;
double size = 0;
const char *units[] = {"B ", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
int i = 0;
char owner[] = "---", group[] = "---", others[] = "---";
/* Get entry's information. */
if ( -1 == lstat( path, &statbuf ) ) {
fprintf( stderr, "printFSObjectInfo: error: can't stat %s\n", path );
if( 0 == strformat( &fbuf, "lstat() said: %s", path ) ) { perror(fbuf); return -1; }
}
// File type
if( S_ISREG(statbuf.st_mode) ) type = "-"; // regular file
if( S_ISDIR(statbuf.st_mode) ) { // directory
type="d";
if( S_ISCDF(statbuf.st_mode) ) type = "hd"; // hidden dir
}
if( S_ISBLK(statbuf.st_mode) ) type = "b"; // block special
if( S_ISCHR(statbuf.st_mode) ) type = "c"; // character special
if( S_ISFIFO(statbuf.st_mode) ) type = "f"; // pipe or FIFO
if( S_ISLNK(statbuf.st_mode) ) type = "l"; // symbolic link
if( S_ISSOCK(statbuf.st_mode) ) type = "s"; // socket
if( S_ISNWK(statbuf.st_mode) ) type = "n"; // network special
printf( "%2s ", type );
/* Print out type, permissions, and number of links. */
//printf("%10.10s", sperm (statbuf.st_mode));
if( S_IRUSR & statbuf.st_mode ) owner[0] = 'r';
if( S_IWUSR & statbuf.st_mode ) owner[1] = 'w';
if( S_IXUSR & statbuf.st_mode ) owner[2] = 'x';
if( S_IRGRP & statbuf.st_mode ) group[0] = 'r';
if( S_IWGRP & statbuf.st_mode ) group[1] = 'w';
if( S_IXGRP & statbuf.st_mode ) group[2] = 'x';
if( S_IROTH & statbuf.st_mode ) others[0] = 'r';
if( S_IWOTH & statbuf.st_mode ) others[1] = 'w';
if( S_IXOTH & statbuf.st_mode ) others[2] = 'x';
//printf( "\n%o\n", statbuf.st_mode );
printf( "%3o %s/%s/%s ", 0777 & statbuf.st_mode, owner, group, others );
printf("%4dL", statbuf.st_nlink);
/* Print out owner's name if it is found using getpwuid(). */
if ((pwd = getpwuid(statbuf.st_uid)) != NULL)
printf(" %-8.8s", pwd->pw_name);
else
printf(" %-8d", statbuf.st_uid);
/* Print out group name if it is found using getgrgid(). */
if ((grp = getgrgid(statbuf.st_gid)) != NULL)
printf(" %-8.8s", grp->gr_name);
else
printf(" %-8d", statbuf.st_gid);
/* Print size of file. */
//printf(" %9d", (int)statbuf.st_size);
i = 0;
size = (double) statbuf.st_size;
while (size >= 1024) {
size /= 1024;
i++;
}
if( 0 == (double)(size - (long) size) )
printf( "%7d %-2s", (long)size, units[i] );
else printf( "%7.2f %-2s", size, units[i] );
tm = localtime(&statbuf.st_mtime);
/* Get localized date string. */
strftime(datestring, sizeof(datestring), "%Y.%m.%d %T", tm); // nl_langinfo(D_T_FMT)
if ( 0 == strcmp(name, "\n") )
printf(" %s > %s", datestring, path);
else {
if( 0 == strcmp(type, "d") ) printf(" %s %s/", datestring, name);
else printf(" %s %s", datestring, name);
}
if( 0 == strcmp(type, "l") ) {
char buf[1+PATH_MAX];
if( -1 == readlink( path, buf, (1+PATH_MAX) ) ) {
fprintf( stderr, "printFSObjectInfo: error: can't read symbolic link %s\n", path);
if( 0 == strformat( &fbuf, "readlink() said: %s:", path ) ) { perror(fbuf); return -2; }
}
else {
lstat( buf, &statbuf ); // want errno, a symlink may point to non-existing object
if(errno == ENOENT) printf(" -> %s [!no such file!]\n", buf );
else {
printf(" -> %s\n", buf );
if ( 0 != strcmp(name, "\n") ) printFSObjectInfo( buf, "\n" );
}
}
}
else printf("\n");
return 0;
}
int main(int argc, char **argv) {
struct dirent *dp;
struct stat statbuf;
char *path = NULL; //[1+PATH_MAX];
char *fbuf = NULL;
char *pathArg = NULL;
if( argc == 1 || 0 == strlen(argv[1]) ) pathArg = ".";
else pathArg = argv[1];
if ( lstat( pathArg, &statbuf ) == -1 ) {
printf("%s: error: can't stat %s\n", argv[0], pathArg);
if( 0 == strformat( &fbuf, "stat() said: %s", pathArg ) ) perror(fbuf);
exit(2);
}
if( S_ISDIR(statbuf.st_mode) ) {
DIR *dir = opendir( pathArg );
if( NULL == dir ) {
fprintf( stderr, "%s: error: can't open %s\n", argv[0], pathArg );
if( 0 != strformat( &fbuf, "opendir() said: %s", pathArg ) ) exit(5);
perror(fbuf);
exit(4);
}
/* Loop through directory entries. */
while ( (dp = readdir(dir)) != NULL ) {
if( 0!= strformat( &path, "%s/%s", pathArg, dp->d_name ) ) continue;
printFSObjectInfo( path, dp->d_name );
}
closedir(dir);
} else printFSObjectInfo( pathArg, pathArg );
return 0;
}
In printFSObjectInfo() you have full functionality of lstat() system call, you can customize this to your wishes.
Be well.
Try a perl one-liner:
perl -e '#d=localtime ((stat(shift))[9]); printf "%02d-%02d-%04d %02d:%02d:%02d\n", $d[3],$d[4]+1,$d[5]+1900,$d[2],$d[1],$d[0]' your_file_to_show_the_date_for.your_extension
ls -le works if you need only HH:MM:SS
On Mac OS X (tested on 10.10.5 Yosemite thru 10.12.4 Sierra):
prompt> ls -lT
total 0
-rw-r--r-- 1 youruser staff 0 Sep 24 10:28:30 2015 my_file_1.txt
-rw-r--r-- 1 youruser staff 0 Sep 24 10:28:35 2015 my_file_2.txt
If you are using HP-UX:
Ok let's say that the name of the file is "junk". On HP-UX you can do:
perl -e '#d=localtime ((stat(shift))[9]); printf "%4d-%02d-%02d %02d:%02d:%02d\n", $d[5]+1900,$d[4]+1,$d[3],$d[2],$d[1],$d[0]' junk
And yes, perl comes with HP-UX. It is in /usr/contrib. But you may have a more recent version in /usr/local or /opt.
Source: Perderabo
Today I encountered the same issue on an old version of HP-UX. The stat program was not part of the installation. (just the C version)
The quickest solution for me was to use a tool such as Tectia file transfer running on my laptop, without actually doing any copying, It converts the time of last modification for you from HP-UX and provides dates and times for all files once you have logged into UNIX.
Possibly this works with other similar graphic based file transfer tools, but I have not tried yet.
On AIX the istat command does this:
machine:~/support> istat ../core
Inode 30034 on device 32/3 File
Protection: rw-rw-r--
Owner: 500(group) Group: 500(user)
Link count: 1 Length 10787748 bytes
Last updated: Wed Feb 22 13:54:28 2012
Last modified: Wed Feb 22 13:54:28 2012
Last accessed: Wed Feb 22 19:58:10 2012
Seconds:
date +%s -r /etc/passwd
Or, with more precision (up to nanosecond precision), if your filesystem supports it:
date +%s.%N -r /etc/passwd

Resources