13
13
#include <unistd.h>
14
14
#include <inttypes.h>
15
15
#include <linux/limits.h>
16
+ #include <time.h>
16
17
17
18
#include "common.h"
18
19
#include "nvme.h"
@@ -122,7 +123,7 @@ struct nlog_dump_header4_1 {
122
123
123
124
struct config {
124
125
__u32 namespace_id ;
125
- char * file_prefix ;
126
+ char * dir_prefix ;
126
127
char * type ;
127
128
bool verbose ;
128
129
};
@@ -222,6 +223,7 @@ static int dump_assert_logs(struct nvme_dev *dev, struct config cfg)
222
223
__u8 buf [INTERNAL_LOG_MAX_BYTE_TRANSFER ];
223
224
__u8 head_buf [INTERNAL_LOG_MAX_BYTE_TRANSFER ];
224
225
char file_path [PATH_MAX ];
226
+ char file_name [] = "AssertLog.bin" ;
225
227
struct assert_dump_header * ad = (struct assert_dump_header * ) head_buf ;
226
228
struct nvme_passthru_cmd cmd = {
227
229
.opcode = 0xd2 ,
@@ -236,7 +238,8 @@ static int dump_assert_logs(struct nvme_dev *dev, struct config cfg)
236
238
if (err )
237
239
return err ;
238
240
239
- sprintf (file_path , "%s_AssertLog.bin" , cfg .file_prefix );
241
+ snprintf (file_path , sizeof (file_path ), "%.*s/%s" ,
242
+ (int ) (sizeof (file_path ) - sizeof (file_name ) - 1 ), cfg .dir_prefix , file_name );
240
243
output = open (file_path , O_WRONLY | O_CREAT | O_TRUNC , 0666 );
241
244
if (output < 0 )
242
245
return - errno ;
@@ -291,7 +294,7 @@ static int dump_event_logs(struct nvme_dev *dev, struct config cfg)
291
294
err = read_header (& cmd , dev_fd (dev ));
292
295
if (err )
293
296
return err ;
294
- sprintf (file_path , "%s_EventLog .bin" , cfg .file_prefix );
297
+ snprintf (file_path , sizeof ( file_path ), "%s/EventLog .bin" , cfg .dir_prefix );
295
298
output = open (file_path , O_WRONLY | O_CREAT | O_TRUNC , 0666 );
296
299
if (output < 0 )
297
300
return - errno ;
@@ -387,7 +390,8 @@ static int dump_nlogs(struct nvme_dev *dev, struct config cfg, int core)
387
390
count = nlog_header -> totalnlogs ;
388
391
core_num = core < 0 ? nlog_header -> corecount : 0 ;
389
392
if (!header_size ) {
390
- sprintf (file_path , "%s_NLog.bin" , cfg .file_prefix );
393
+ snprintf (file_path , sizeof (file_path ), "%s/NLog.bin" ,
394
+ cfg .dir_prefix );
391
395
output = open (file_path , O_WRONLY | O_CREAT | O_TRUNC , 0666 );
392
396
if (output < 0 )
393
397
return - errno ;
@@ -423,25 +427,32 @@ enum telemetry_type {
423
427
424
428
static int dump_telemetry (struct nvme_dev * dev , struct config cfg , enum telemetry_type ttype )
425
429
{
426
- struct nvme_telemetry_log * log = NULL ;
430
+ _cleanup_free_ struct nvme_telemetry_log * log = NULL ;
427
431
size_t log_size = 0 ;
428
- int err = 0 , output ;
432
+ int err = 0 ;
429
433
__u8 * buffer = NULL ;
430
434
size_t bytes_remaining = 0 ;
431
435
enum nvme_telemetry_da da ;
432
436
size_t max_data_tx ;
433
437
char file_path [PATH_MAX ];
434
- char * log_name ;
438
+ char * file_name ;
439
+ char * log_descr ;
440
+ struct stat sb ;
441
+
442
+ _cleanup_file_ int output = -1 ;
435
443
436
444
switch (ttype ) {
437
445
case HOSTGENNEW :
438
- log_name = "TelemetryHostGenNew" ;
446
+ file_name = "lid_0x07_lsp_0x01_lsi_0x0000.bin" ;
447
+ log_descr = "Generated Host Initiated" ;
439
448
break ;
440
449
case HOSTGENOLD :
441
- log_name = "TelemetryHostGenOld" ;
450
+ file_name = "lid_0x07_lsp_0x00_lsi_0x0000.bin" ;
451
+ log_descr = "Existing Host Initiated" ;
442
452
break ;
443
453
case CONTROLLER :
444
- log_name = "TelemetryController" ;
454
+ file_name = "lid_0x08_lsp_0x00_lsi_0x0000.bin" ;
455
+ log_descr = "Controller Initiated" ;
445
456
break ;
446
457
default :
447
458
return - EINVAL ;
@@ -453,11 +464,6 @@ static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetr
453
464
if (max_data_tx > DRIVER_MAX_TX_256K )
454
465
max_data_tx = DRIVER_MAX_TX_256K ;
455
466
456
- sprintf (file_path , "%s_%s.bin" , cfg .file_prefix , log_name );
457
- output = open (file_path , O_WRONLY | O_CREAT | O_TRUNC , 0644 );
458
- if (output < 0 )
459
- return - errno ;
460
-
461
467
switch (ttype ) {
462
468
case HOSTGENNEW :
463
469
err = nvme_get_telemetry_log (dev_fd (dev ), true, false, false, max_data_tx , da ,
@@ -474,7 +480,20 @@ static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetr
474
480
}
475
481
476
482
if (err )
477
- goto tele_close_output ;
483
+ return err ;
484
+
485
+ snprintf (file_path , sizeof (file_path ), "%s/log_pages" , cfg .dir_prefix );
486
+ if (!(stat (file_path , & sb ) == 0 && S_ISDIR (sb .st_mode ))) {
487
+ if (mkdir (file_path , 777 ) != 0 ) {
488
+ perror (file_path );
489
+ return - errno ;
490
+ }
491
+ }
492
+
493
+ snprintf (file_path , sizeof (file_path ), "%s/log_pages/%s" , cfg .dir_prefix , file_name );
494
+ output = open (file_path , O_WRONLY | O_CREAT | O_TRUNC , 0644 );
495
+ if (output < 0 )
496
+ return - errno ;
478
497
479
498
bytes_remaining = log_size ;
480
499
buffer = (__u8 * )log ;
@@ -486,45 +505,49 @@ static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetr
486
505
err = - errno ;
487
506
goto tele_close_output ;
488
507
}
508
+
489
509
bytes_remaining -= bytes_written ;
490
510
buffer += bytes_written ;
491
511
}
492
- printf ("Successfully wrote log to %s\n" , file_path );
512
+ printf ("Successfully wrote %s Telemetry log to %s\n" , log_descr , file_path );
493
513
494
514
tele_close_output :
495
- free (log );
496
515
close (output );
497
-
498
516
return err ;
499
517
}
500
518
501
519
int solidigm_get_internal_log (int argc , char * * argv , struct command * command ,
502
520
struct plugin * plugin )
503
521
{
522
+ char folder [PATH_MAX ];
523
+ char zip_name [PATH_MAX ];
524
+ char * output_path ;
504
525
char sn_prefix [sizeof (((struct nvme_id_ctrl * )0 )-> sn )+ 1 ];
505
526
int log_count = 0 ;
506
527
int err ;
507
- struct nvme_dev * dev ;
528
+ _cleanup_nvme_dev_ struct nvme_dev * dev = NULL ;
508
529
bool all = false;
530
+ time_t t ;
531
+ struct tm tm ;
509
532
510
533
const char * desc = "Get Debug Firmware Logs and save them." ;
511
534
const char * type =
512
535
"Log type: ALL, CONTROLLERINITTELEMETRY, HOSTINITTELEMETRY, HOSTINITTELEMETRYNOGEN, NLOG, ASSERT, EVENT. Defaults to ALL." ;
513
- const char * prefix = "Output file prefix; defaults to device serial number." ;
536
+ const char * prefix = "Output dir prefix; defaults to device serial number." ;
514
537
const char * verbose = "To print out verbose info." ;
515
538
const char * namespace_id = "Namespace to get logs from." ;
516
539
517
540
518
541
struct config cfg = {
519
542
.namespace_id = NVME_NSID_ALL ,
520
- .file_prefix = NULL ,
543
+ .dir_prefix = NULL ,
521
544
.type = NULL ,
522
545
};
523
546
524
547
OPT_ARGS (opts ) = {
525
548
OPT_STR ("type" , 't' , & cfg .type , type ),
526
549
OPT_UINT ("namespace-id" , 'n' , & cfg .namespace_id , namespace_id ),
527
- OPT_FILE ("file -prefix" , 'p' , & cfg .file_prefix , prefix ),
550
+ OPT_FILE ("dir -prefix" , 'p' , & cfg .dir_prefix , prefix ),
528
551
OPT_FLAG ("verbose" , 'v' , & cfg .verbose , verbose ),
529
552
OPT_END ()
530
553
};
@@ -533,12 +556,22 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command,
533
556
if (err )
534
557
return err ;
535
558
536
- if (!cfg .file_prefix ) {
559
+ if (!cfg .dir_prefix ) {
537
560
err = get_serial_number (sn_prefix , dev_fd (dev ));
538
561
if (err )
539
- goto out_dev ;
540
- cfg .file_prefix = sn_prefix ;
562
+ return err ;
563
+ cfg .dir_prefix = sn_prefix ;
564
+ }
565
+ t = time (NULL );
566
+ tm = * localtime (& t );
567
+ snprintf (folder , sizeof (folder ), "%s-%d%02d%02d%02d%02d%02d" , cfg .dir_prefix ,
568
+ tm .tm_year + 1900 , tm .tm_mon + 1 , tm .tm_mday , tm .tm_hour , tm .tm_min , tm .tm_sec );
569
+ if (mkdir (folder , 0777 ) != 0 ) {
570
+ perror ("mkdir" );
571
+ return - errno ;
541
572
}
573
+ cfg .dir_prefix = folder ;
574
+ output_path = folder ;
542
575
543
576
if (!cfg .type )
544
577
cfg .type = "ALL" ;
@@ -547,8 +580,9 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command,
547
580
* p = toupper (* p );
548
581
}
549
582
550
- if (!strcmp (cfg .type , "ALL" ))
583
+ if (!strcmp (cfg .type , "ALL" )) {
551
584
all = true;
585
+ }
552
586
if (all || !strcmp (cfg .type , "ASSERT" )) {
553
587
err = dump_assert_logs (dev , cfg );
554
588
if (err == 0 )
@@ -592,14 +626,32 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command,
592
626
perror ("Error retrieving Telemetry Host Initiated" );
593
627
}
594
628
629
+ if (log_count > 0 ) {
630
+ int ret_cmd ;
631
+ char cmd [ARG_MAX ];
632
+ char * where_err = cfg .verbose ? "" : ">/dev/null 2>&1" ;
633
+
634
+ snprintf (zip_name , sizeof (zip_name ), "%s.zip" , cfg .dir_prefix );
635
+ snprintf (cmd , sizeof (cmd ), "cd \"%s\" && zip -r \"../%s\" ./* %s" , cfg .dir_prefix ,
636
+ zip_name , where_err );
637
+ printf ("Compressing logs to %s\n" , zip_name );
638
+ ret_cmd = system (cmd );
639
+ if (ret_cmd == -1 )
640
+ perror (cmd );
641
+ else {
642
+ output_path = zip_name ;
643
+ snprintf (cmd , sizeof (cmd ), "rm -rf %s" , cfg .dir_prefix );
644
+ printf ("Removing %s\n" , cfg .dir_prefix );
645
+ if (system (cmd ) != 0 )
646
+ perror ("Failed removing logs folder" );
647
+ }
648
+ }
649
+
595
650
if (log_count == 0 ) {
596
651
if (err > 0 )
597
652
nvme_show_status (err );
598
653
} else if ((log_count > 1 ) || cfg .verbose )
599
- printf ("Total: %d log files with prefix: %s\n" , log_count , cfg .file_prefix );
600
- out_dev :
601
- /* Redundant close() to make static code analysis happy */
602
- close (dev -> direct .fd );
603
- dev_close (dev );
654
+ printf ("Total: %d log files in %s\n" , log_count , output_path );
655
+
604
656
return err ;
605
657
}
0 commit comments