@@ -416,12 +416,41 @@ static size_t append_to_file(struct lightningd *ld,
416416 return strcount (buffer , "\n" ) + 1 ;
417417}
418418
419+ static const char * grab_and_check (const tal_t * ctx ,
420+ const char * fname ,
421+ size_t linenum ,
422+ const char * expected ,
423+ char * * * lines )
424+ {
425+ char * contents ;
426+
427+ contents = grab_file (tmpctx , fname );
428+ if (!contents )
429+ return tal_fmt (ctx , "Could not load configfile %s: %s" ,
430+ fname , strerror (errno ));
431+
432+ /* These are 1-based! */
433+ assert (linenum > 0 );
434+ * lines = tal_strsplit (ctx , contents , "\r\n" , STR_EMPTY_OK );
435+ if (linenum >= tal_count (* lines ))
436+ return tal_fmt (ctx , "Configfile %s no longer has %zu lines!" ,
437+ fname , linenum );
438+
439+ if (!streq ((* lines )[linenum - 1 ], expected ))
440+ return tal_fmt (ctx , "Configfile %s line %zu changed from %s to %s!" ,
441+ fname , linenum ,
442+ expected ,
443+ (* lines )[linenum - 1 ]);
444+ return NULL ;
445+ }
446+
419447/* This comments out the config file entry or maybe replace one */
420448static void configfile_replace_var (struct lightningd * ld ,
421449 const struct configvar * cv ,
422450 const char * replace )
423451{
424- char * contents , * * lines , * template ;
452+ char * * lines , * template , * contents ;
453+ const char * err ;
425454 int outfd ;
426455
427456 switch (cv -> src ) {
@@ -437,21 +466,11 @@ static void configfile_replace_var(struct lightningd *ld,
437466 break ;
438467 }
439468
440- contents = grab_file (tmpctx , cv -> file );
441- if (!contents )
442- fatal ("Could not load configfile %s: %s" ,
443- cv -> file , strerror (errno ));
444-
445- lines = tal_strsplit (contents , contents , "\r\n" , STR_EMPTY_OK );
446- if (cv -> linenum - 1 >= tal_count (lines ))
447- fatal ("Configfile %s no longer has %u lines!" ,
448- cv -> file , cv -> linenum );
449-
450- if (!streq (lines [cv -> linenum - 1 ], cv -> configline ))
451- fatal ("Configfile %s line %u changed from %s to %s!" ,
452- cv -> file , cv -> linenum ,
453- cv -> configline ,
454- lines [cv -> linenum - 1 ]);
469+ /* If it changed *now*, that's fatal: we already set it locally! */
470+ err = grab_and_check (tmpctx , cv -> file , cv -> linenum , cv -> configline ,
471+ & lines );
472+ if (err )
473+ fatal ("%s" , err );
455474
456475 if (replace )
457476 lines [cv -> linenum - 1 ] = cast_const (char * , replace );
@@ -595,14 +614,12 @@ static bool dir_writable(const char *fname)
595614/* Returns config file name if not writable */
596615static const char * config_not_writable (const tal_t * ctx ,
597616 struct command * cmd ,
598- const struct opt_table * ot )
617+ const struct configvar * oldcv )
599618{
600619 struct lightningd * ld = cmd -> ld ;
601- struct configvar * oldcv ;
602620 const char * fname ;
603621
604622 /* If it exists before, we will need to replace that file (rename) */
605- oldcv = configvar_first (ld -> configvars , opt_names_arr (tmpctx , ot ));
606623 if (oldcv && oldcv -> file ) {
607624 /* We will rename */
608625 if (!dir_writable (oldcv -> file ))
@@ -645,11 +662,32 @@ static struct command_result *json_setconfig(struct command *cmd,
645662 assert (!(ot -> type & OPT_MULTI ));
646663
647664 if (!* transient ) {
648- const char * fname = config_not_writable (cmd , cmd , ot );
665+ const struct configvar * cv ;
666+ const char * fname ;
667+
668+ cv = configvar_first (cmd -> ld -> configvars ,
669+ opt_names_arr (tmpctx , ot ));
670+
671+ fname = config_not_writable (cmd , cmd , cv );
649672 if (fname )
650673 return command_fail (cmd , JSONRPC2_INVALID_PARAMS ,
651674 "Cannot write to config file %s" ,
652675 fname );
676+
677+ /* Check if old config has changed (so we couldn't be able
678+ * to comment it out! */
679+ if (cv && cv -> file ) {
680+ const char * changed ;
681+ char * * lines ;
682+
683+ changed = grab_and_check (tmpctx ,
684+ cv -> file , cv -> linenum ,
685+ cv -> configline ,
686+ & lines );
687+ if (changed )
688+ return command_fail (cmd , JSONRPC2_INVALID_PARAMS ,
689+ "%s" , changed );
690+ }
653691 }
654692
655693 /* We use arg = NULL to tell callback it's only for testing */
0 commit comments