@@ -162,6 +162,9 @@ struct set_reg_config {
162162 __u32 pmrmscu ;
163163};
164164
165+ #define NVME_OUT "nvme.out"
166+ #define NVME_PREV_OUT "nvme-prev.out"
167+
165168static const char nvme_version_string [] = NVME_VERSION ;
166169
167170static struct plugin builtin = {
@@ -191,6 +194,7 @@ const char *output_format = "Output format: normal|binary";
191194const char * timeout = "timeout value, in milliseconds" ;
192195const char * verbose = "Increase output verbosity" ;
193196const char * dry_run = "show command instead of sending" ;
197+ const char * delay = "iterative delay as SECS [.TENTHS]" ;
194198
195199static const char * app_tag = "app tag for end-to-end PI" ;
196200static const char * app_tag_mask = "app tag mask for end-to-end PI" ;
@@ -262,6 +266,7 @@ struct nvme_config nvme_cfg = {
262266 .output_format = "normal" ,
263267 .output_format_ver = 1 ,
264268 .timeout = NVME_DEFAULT_IOCTL_TIMEOUT ,
269+ .delay = 0 ,
265270};
266271
267272static void * mmap_registers (struct nvme_transport_handle * hdl , bool writable );
@@ -362,6 +367,16 @@ static int get_transport_handle(struct nvme_global_ctx *ctx, int argc,
362367 return ret ;
363368}
364369
370+ static int set_stdout_file (void )
371+ {
372+ if (!freopen (NVME_OUT , "w" , stdout )) {
373+ perror ("freopen" );
374+ return - errno ;
375+ }
376+
377+ return 0 ;
378+ }
379+
365380static int parse_args (int argc , char * argv [], const char * desc ,
366381 struct argconfig_commandline_options * opts )
367382{
@@ -374,7 +389,10 @@ static int parse_args(int argc, char *argv[], const char *desc,
374389 log_level = map_log_level (nvme_cfg .verbose , false);
375390 nvme_init_default_logging (stderr , log_level , false, false);
376391
377- return 0 ;
392+ if (nvme_cfg .delay )
393+ ret = set_stdout_file ();
394+
395+ return ret ;
378396}
379397
380398int parse_and_open (struct nvme_global_ctx * * ctx ,
@@ -9998,7 +10016,7 @@ static int tls_key(int argc, char **argv, struct command *acmd, struct plugin *p
999810016 OPT_FLAG ("export" , 'e' , & cfg .export , export ),
999910017 OPT_STR ("revoke" , 'r' , & cfg .revoke , revoke ));
1000010018
10001- err = argconfig_parse (argc , argv , desc , opts );
10019+ err = parse_args (argc , argv , desc , opts );
1000210020 if (err )
1000310021 return err ;
1000410022
@@ -10096,9 +10114,10 @@ static int show_topology_cmd(int argc, char **argv, struct command *acmd, struct
1009610114 };
1009710115
1009810116 NVME_ARGS (opts ,
10099- OPT_FMT ("ranking" , 'r' , & cfg .ranking , ranking ));
10117+ OPT_FMT ("ranking" , 'r' , & cfg .ranking , ranking ),
10118+ OPT_DOUBLE ("delay" , 'd' , & nvme_cfg .delay , delay ));
1010010119
10101- err = argconfig_parse (argc , argv , desc , opts );
10120+ err = parse_args (argc , argv , desc , opts );
1010210121 if (err )
1010310122 return err ;
1010410123
@@ -11011,6 +11030,118 @@ void register_extension(struct plugin *plugin)
1101111030 nvme .extensions -> tail = plugin ;
1101211031}
1101311032
11033+ static char * read_file (const char * file , size_t * len )
11034+ {
11035+ struct stat st ;
11036+ char * buf ;
11037+ FILE * fp ;
11038+
11039+ fp = fopen (file , "r" );
11040+ if (!fp || stat (file , & st ))
11041+ return NULL ;
11042+
11043+ buf = malloc (st .st_size );
11044+ if (!buf )
11045+ return NULL ;
11046+
11047+ * len = fread (buf , 1 , st .st_size , fp );
11048+ if (* len )
11049+ return buf ;
11050+
11051+ free (buf );
11052+ return NULL ;
11053+ }
11054+
11055+ static bool delay_compare (void )
11056+ {
11057+ _cleanup_free_ char * prev_buf = NULL ;
11058+ _cleanup_free_ char * buf = NULL ;
11059+ size_t prev_len ;
11060+ struct stat st ;
11061+ size_t len ;
11062+
11063+ if (stat (NVME_PREV_OUT , & st ))
11064+ return true;
11065+
11066+ buf = read_file (NVME_OUT , & len );
11067+ if (!buf )
11068+ return true;
11069+
11070+ prev_buf = read_file (NVME_PREV_OUT , & prev_len );
11071+ if (!prev_buf || len != prev_len )
11072+ return true;
11073+
11074+ return !!memcmp (buf , prev_buf , len );
11075+ }
11076+
11077+ static bool delay_copy (void )
11078+ {
11079+ _cleanup_free_ char * cmd = NULL ;
11080+ int err ;
11081+
11082+ if (asprintf (& cmd , "cp %s %s" , NVME_OUT , NVME_PREV_OUT ) < 0 )
11083+ return false;
11084+
11085+ err = system (cmd );
11086+ if (err < 0 )
11087+ return false;
11088+
11089+ return true;
11090+ }
11091+
11092+ static bool delay_print (void )
11093+ {
11094+ size_t len ;
11095+ _cleanup_free_ char * buf = read_file (NVME_OUT , & len );
11096+ int err ;
11097+
11098+ err = system ("clear" );
11099+ if (err < 0 )
11100+ return false;
11101+
11102+ printf ("%s" , buf );
11103+
11104+ return true;
11105+ }
11106+
11107+ static bool handle_delay (void )
11108+ {
11109+ struct timespec ts ;
11110+ double delay_f ;
11111+ double delay_i ;
11112+ int err ;
11113+
11114+ if (!freopen ("/dev/tty" , "w" , stdout ))
11115+ return false;
11116+
11117+ if (delay_compare ()) {
11118+ if (!delay_print () || !delay_copy ())
11119+ return false;
11120+ }
11121+
11122+ delay_f = modf (nvme_cfg .delay , & delay_i );
11123+ ts .tv_sec = delay_i ;
11124+ ts .tv_nsec = delay_f * 1000000000 ;
11125+ err = pselect (0 , NULL , NULL , NULL , & ts , NULL );
11126+ if (err < 0 )
11127+ return false;
11128+
11129+ return true;
11130+ }
11131+
11132+ static int remove_file (void )
11133+ {
11134+ struct stat st ;
11135+
11136+ if (!stat (NVME_OUT , & st ) && remove (NVME_OUT ))
11137+ return - errno ;
11138+
11139+ if (!stat (NVME_PREV_OUT , & st ) && remove (NVME_PREV_OUT ))
11140+ return - errno ;
11141+
11142+ return 0 ;
11143+ }
11144+
1101411145int main (int argc , char * * argv )
1101511146{
1101611147 int err ;
@@ -11026,9 +11157,15 @@ int main(int argc, char **argv)
1102611157 if (err )
1102711158 return err ;
1102811159
11029- err = handle_plugin (argc - 1 , & argv [1 ], nvme .extensions );
11030- if (err == - ENOTTY )
11031- general_help (& builtin , NULL );
11160+ err = remove_file ();
11161+ if (err )
11162+ return err ;
11163+
11164+ do {
11165+ err = handle_plugin (argc - 1 , & argv [1 ], nvme .extensions );
11166+ if (err == - ENOTTY )
11167+ general_help (& builtin , NULL );
11168+ } while (!err && nvme_cfg .delay && handle_delay ());
1103211169
1103311170 return err ? 1 : 0 ;
1103411171}
0 commit comments