@@ -1865,6 +1865,180 @@ int human_readable_size(SZOFFTYPE sz, int print, int col) {
18651865 return strlen (buf );
18661866}
18671867
1868+ /*
1869+ * json_print_file() - print a single file entry as JSON fields
1870+ */
1871+ static void json_print_file (struct lsof_context * ctx , int * sep ) {
1872+ char buf [128 ];
1873+ char fd_str [FDLEN ];
1874+ char type [TYPEL ];
1875+ char * cp ;
1876+ unsigned long ul ;
1877+
1878+ if (FieldSel [LSOF_FIX_FD ].st ) {
1879+ if (Lf -> fd_type == LSOF_FD_NUMERIC ) {
1880+ char num_buf [32 ];
1881+ snprintf (num_buf , sizeof (num_buf ), "%d" , Lf -> fd_num );
1882+ json_print_str (sep , "fd" , num_buf );
1883+ } else {
1884+ fd_to_string (Lf -> fd_type , Lf -> fd_num , fd_str );
1885+ json_print_str (sep , "fd" , fd_str );
1886+ }
1887+ }
1888+ if (FieldSel [LSOF_FIX_ACCESS ].st ) {
1889+ char a [2 ] = {access_to_char (Lf -> access ), '\0' };
1890+ if (a [0 ] != ' ' )
1891+ json_print_str (sep , "access" , a );
1892+ }
1893+ if (FieldSel [LSOF_FIX_LOCK ].st ) {
1894+ char l [2 ] = {lock_to_char (Lf -> lock ), '\0' };
1895+ if (l [0 ] != ' ' )
1896+ json_print_str (sep , "lock" , l );
1897+ }
1898+ if (FieldSel [LSOF_FIX_TYPE ].st && Lf -> type != LSOF_FILE_NONE ) {
1899+ file_type_to_string (Lf -> type , Lf -> unknown_file_type_number , type ,
1900+ TYPEL );
1901+ json_print_str (sep , "type" , type );
1902+ }
1903+ if (FieldSel [LSOF_FIX_DEVCH ].st && Lf -> dev_ch && Lf -> dev_ch [0 ]) {
1904+ for (cp = Lf -> dev_ch ; * cp == ' ' ; cp ++ )
1905+ ;
1906+ if (* cp )
1907+ json_print_str (sep , "device" , cp );
1908+ }
1909+ if (FieldSel [LSOF_FIX_DEVN ].st && Lf -> dev_def ) {
1910+ if (sizeof (unsigned long ) > sizeof (dev_t ))
1911+ ul = (unsigned long )((unsigned int )Lf -> dev );
1912+ else
1913+ ul = (unsigned long )Lf -> dev ;
1914+ snprintf (buf , sizeof (buf ), "0x%lx" , ul );
1915+ json_print_str (sep , "device_number" , buf );
1916+ }
1917+ if (FieldSel [LSOF_FIX_RDEV ].st && Lf -> rdev_def ) {
1918+ if (sizeof (unsigned long ) > sizeof (dev_t ))
1919+ ul = (unsigned long )((unsigned int )Lf -> rdev );
1920+ else
1921+ ul = (unsigned long )Lf -> rdev ;
1922+ snprintf (buf , sizeof (buf ), "0x%lx" , ul );
1923+ json_print_str (sep , "raw_device" , buf );
1924+ }
1925+ if (FieldSel [LSOF_FIX_SIZE ].st && Lf -> sz_def ) {
1926+ json_print_uint64_str (sep , "size" , (uint64_t )Lf -> sz );
1927+ }
1928+ if (FieldSel [LSOF_FIX_OFFSET ].st && Lf -> off_def ) {
1929+ json_print_uint64_str (sep , "offset" , (uint64_t )Lf -> off );
1930+ }
1931+ if (FieldSel [LSOF_FIX_INODE ].st && Lf -> inp_ty == 1 ) {
1932+ json_print_uint64_str (sep , "inode" , (uint64_t )Lf -> inode );
1933+ }
1934+ if (FieldSel [LSOF_FIX_NLINK ].st && Lf -> nlink_def ) {
1935+ json_print_long (sep , "nlink" , Lf -> nlink );
1936+ }
1937+ if (FieldSel [LSOF_FIX_PROTO ].st && Lf -> inp_ty == 2 ) {
1938+ for (cp = Lf -> iproto ; * cp == ' ' ; cp ++ )
1939+ ;
1940+ if (* cp )
1941+ json_print_str (sep , "protocol" , cp );
1942+ }
1943+
1944+ #if defined(HASFSTRUCT )
1945+ if (FieldSel [LSOF_FIX_FG ].st && (Fsv & FSV_FG ) && (Lf -> fsv & FSV_FG ) &&
1946+ (FsvFlagX || Lf -> ffg || Lf -> pof )) {
1947+ json_print_str (sep , "flags" , print_fflags (ctx , Lf -> ffg , Lf -> pof ));
1948+ }
1949+ #endif /* defined(HASFSTRUCT) */
1950+
1951+ if (FieldSel [LSOF_FIX_NAME ].st && Lf -> nm ) {
1952+ json_print_str (sep , "name" , Lf -> nm );
1953+ }
1954+
1955+ /* TCP/TPI info as nested object */
1956+ if (Lf -> lts .type >= 0 && FieldSel [LSOF_FIX_TCPTPI ].st ) {
1957+ if (* sep )
1958+ putchar (',' );
1959+ printf ("\"tcp_info\":{" );
1960+ int tsep = 0 ;
1961+
1962+ if ((Ftcptpi & TCPTPI_STATE ) && Lf -> lts .type == 0 ) {
1963+ if (!TcpNstates )
1964+ (void )build_IPstates (ctx );
1965+ int s = Lf -> lts .state .i ;
1966+ if (s >= 0 && s < TcpNstates && TcpSt [s ])
1967+ json_print_str (& tsep , "state" , TcpSt [s ]);
1968+ else {
1969+ snprintf (buf , sizeof (buf ), "UNKNOWN_%d" , s );
1970+ json_print_str (& tsep , "state" , buf );
1971+ }
1972+ }
1973+ #if defined(HASTCPTPIQ )
1974+ if (Ftcptpi & TCPTPI_QUEUES ) {
1975+ if (Lf -> lts .rqs )
1976+ json_print_ulong (& tsep , "recv_queue" , Lf -> lts .rq );
1977+ if (Lf -> lts .sqs )
1978+ json_print_ulong (& tsep , "send_queue" , Lf -> lts .sq );
1979+ }
1980+ #endif /* defined(HASTCPTPIQ) */
1981+ #if defined(HASTCPTPIW )
1982+ if (Ftcptpi & TCPTPI_WINDOWS ) {
1983+ if (Lf -> lts .rws )
1984+ json_print_ulong (& tsep , "read_window" , Lf -> lts .rw );
1985+ if (Lf -> lts .wws )
1986+ json_print_ulong (& tsep , "write_window" , Lf -> lts .ww );
1987+ }
1988+ #endif /* defined(HASTCPTPIW) */
1989+ putchar ('}' );
1990+ * sep = 1 ;
1991+ }
1992+ }
1993+
1994+ /*
1995+ * json_print_proc_fields() - print process-level JSON fields
1996+ */
1997+ static void json_print_proc_fields (struct lsof_context * ctx , int * sep ) {
1998+ int ty ;
1999+ char * cp ;
2000+
2001+ if (FieldSel [LSOF_FIX_PID ].st )
2002+ json_print_int (sep , "pid" , Lp -> pid );
2003+
2004+ #if defined(HASTASKS )
2005+ if (FieldSel [LSOF_FIX_TID ].st && Lp -> tid )
2006+ json_print_int (sep , "tid" , Lp -> tid );
2007+ if (FieldSel [LSOF_FIX_TCMD ].st && Lp -> tcmd )
2008+ json_print_str (sep , "task_cmd" , Lp -> tcmd );
2009+ #endif
2010+
2011+ #if defined(HASZONES )
2012+ if (FieldSel [LSOF_FIX_ZONE ].st && Fzone && Lp -> zn )
2013+ json_print_str (sep , "zone" , Lp -> zn );
2014+ #endif
2015+
2016+ #if defined(HASSELINUX )
2017+ if (FieldSel [LSOF_FIX_CNTX ].st && Fcntx && Lp -> cntx && CntxStatus )
2018+ json_print_str (sep , "security_context" , Lp -> cntx );
2019+ #endif
2020+
2021+ if (FieldSel [LSOF_FIX_PGID ].st && Fpgid )
2022+ json_print_int (sep , "pgid" , Lp -> pgid );
2023+
2024+ #if defined(HASPPID )
2025+ if (FieldSel [LSOF_FIX_PPID ].st && Fppid )
2026+ json_print_int (sep , "ppid" , Lp -> ppid );
2027+ #endif
2028+
2029+ if (FieldSel [LSOF_FIX_CMD ].st )
2030+ json_print_str (sep , "command" , Lp -> cmd ? Lp -> cmd : "(unknown)" );
2031+
2032+ if (FieldSel [LSOF_FIX_UID ].st )
2033+ json_print_int (sep , "uid" , (int )Lp -> uid );
2034+
2035+ if (FieldSel [LSOF_FIX_LOGIN ].st ) {
2036+ cp = printuid (ctx , (UID_ARG )Lp -> uid , & ty );
2037+ if (ty == 0 )
2038+ json_print_str (sep , "login" , cp );
2039+ }
2040+ }
2041+
18682042/*
18692043 * print_proc() - print process
18702044 */
@@ -1898,6 +2072,56 @@ int print_proc(struct lsof_context *ctx) {
18982072 }
18992073 return (0 );
19002074 }
2075+ /*
2076+ * JSON output modes — only emit on PrPass 1 (actual printing pass)
2077+ */
2078+ if ((Fjson || Fjsonl ) && PrPass ) {
2079+ for (Lf = Lp -> file ; Lf ; Lf = Lf -> next ) {
2080+ if (is_file_sel (ctx , Lp , Lf ))
2081+ break ;
2082+ }
2083+ if (!Lf )
2084+ return (rv );
2085+ rv = 1 ;
2086+
2087+ if (Fjson ) {
2088+ /* Nested JSON: process object with files array */
2089+ if (!Fjson_first_proc )
2090+ putchar (',' );
2091+ Fjson_first_proc = 0 ;
2092+ int sep = 0 ;
2093+ putchar ('{' );
2094+ json_print_proc_fields (ctx , & sep );
2095+ if (sep )
2096+ putchar (',' );
2097+ printf ("\"files\":[" );
2098+ int first_file = 1 ;
2099+ for (Lf = Lp -> file ; Lf ; Lf = Lf -> next ) {
2100+ if (!is_file_sel (ctx , Lp , Lf ))
2101+ continue ;
2102+ if (!first_file )
2103+ putchar (',' );
2104+ putchar ('{' );
2105+ int fsep = 0 ;
2106+ json_print_file (ctx , & fsep );
2107+ putchar ('}' );
2108+ first_file = 0 ;
2109+ }
2110+ printf ("]}" );
2111+ } else {
2112+ /* JSON Lines: one line per file, process fields denormalized */
2113+ for (Lf = Lp -> file ; Lf ; Lf = Lf -> next ) {
2114+ if (!is_file_sel (ctx , Lp , Lf ))
2115+ continue ;
2116+ int sep = 0 ;
2117+ putchar ('{' );
2118+ json_print_proc_fields (ctx , & sep );
2119+ json_print_file (ctx , & sep );
2120+ printf ("}\n" );
2121+ }
2122+ }
2123+ return (rv );
2124+ }
19012125 /*
19022126 * If fields have been selected, output the process-only ones, provided
19032127 * that some file has also been selected.
0 commit comments