@@ -1036,6 +1036,62 @@ static int svc_compare(svc_t *svc, char *arg)
10361036 return 0 ;
10371037}
10381038
1039+ /*
1040+ * Escape a string for safe JSON output. Handles quotes, backslashes,
1041+ * and control characters. Returns pointer to static buffer.
1042+ */
1043+ static char * json_escape (const char * str )
1044+ {
1045+ static char buf [1024 ];
1046+ char * ptr = buf ;
1047+ size_t left = sizeof (buf ) - 1 ;
1048+
1049+ if (!str )
1050+ return "" ;
1051+
1052+ while (* str && left > 1 ) {
1053+ char c = * str ++ ;
1054+
1055+ switch (c ) {
1056+ case '"' :
1057+ case '\\' :
1058+ * ptr ++ = '\\' ;
1059+ * ptr ++ = c ;
1060+ left -= 2 ;
1061+ break ;
1062+ case '\n' :
1063+ * ptr ++ = '\\' ;
1064+ * ptr ++ = 'n' ;
1065+ left -= 2 ;
1066+ break ;
1067+ case '\r' :
1068+ * ptr ++ = '\\' ;
1069+ * ptr ++ = 'r' ;
1070+ left -= 2 ;
1071+ break ;
1072+ case '\t' :
1073+ * ptr ++ = '\\' ;
1074+ * ptr ++ = 't' ;
1075+ left -= 2 ;
1076+ break ;
1077+ default :
1078+ if ((unsigned char )c < 0x20 ) {
1079+ /* Other control chars: use \uXXXX */
1080+ int n = snprintf (ptr , left , "\\u%04x" , (unsigned char )c );
1081+ ptr += n ;
1082+ left -= n ;
1083+ } else {
1084+ * ptr ++ = c ;
1085+ left -- ;
1086+ }
1087+ break ;
1088+ }
1089+ }
1090+ * ptr = '\0' ;
1091+
1092+ return buf ;
1093+ }
1094+
10391095static int json_status_one (FILE * fp , svc_t * svc , char * indent , int prev )
10401096{
10411097 long now = jiffies ();
@@ -1051,14 +1107,16 @@ static int json_status_one(FILE *fp, svc_t *svc, char *indent, int prev)
10511107 fprintf (fp ,
10521108 "%s"
10531109 "%s{\n"
1054- "%s \"identity\": \"%s\",\n"
1055- "%s \"description\": \"%s\",\n"
1110+ "%s \"identity\": \"%s\",\n" ,
1111+ prev ? ",\n" : indent , prev ? indent : "" ,
1112+ indent , svc_ident (svc , NULL , 0 ));
1113+ fprintf (fp ,
1114+ "%s \"description\": \"%s\",\n" ,
1115+ indent , json_escape (svc -> desc ));
1116+ fprintf (fp ,
10561117 "%s \"type\": \"%s\",\n"
10571118 "%s \"forking\": %s,\n"
10581119 "%s \"status\": \"%s\",\n" ,
1059- prev ? ",\n" : indent , prev ? indent : "" ,
1060- indent , svc_ident (svc , NULL , 0 ),
1061- indent , svc -> desc ,
10621120 indent , svc_typestr (svc ),
10631121 indent , svc -> forking ? "true" : "false" ,
10641122 indent , svc_status (svc ));
@@ -1080,15 +1138,17 @@ static int json_status_one(FILE *fp, svc_t *svc, char *indent, int prev)
10801138 }
10811139
10821140 fprintf (fp ,
1083- "%s \"origin\": \"%s\",\n"
1141+ "%s \"origin\": \"%s\",\n" ,
1142+ indent , svc -> file [0 ] ? svc -> file : "built-in" );
1143+ svc_command (svc , buf , sizeof (buf ), 0 );
1144+ fprintf (fp ,
10841145 "%s \"command\": \"%s\",\n" ,
1085- indent , svc -> file [0 ] ? svc -> file : "built-in" ,
1086- indent , svc_command (svc , buf , sizeof (buf ), 0 ));
1146+ indent , json_escape (buf ));
10871147
10881148 svc_environ (svc , buf , sizeof (buf ), 0 );
10891149 if (buf [0 ])
10901150 fprintf (fp ,
1091- "%s \"environment\": \"%s\",\n" , indent , buf );
1151+ "%s \"environment\": \"%s\",\n" , indent , json_escape ( buf ) );
10921152
10931153 svc_cond (svc , buf , sizeof (buf ), 0 );
10941154 if (buf [0 ])
0 commit comments