diff --git a/.gitignore b/.gitignore index 5dc47eae..de23aaab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.DS_Store *~ .*.swp Doxyfile diff --git a/AUTHORS b/AUTHORS index 8d430019..09bc0a58 100644 --- a/AUTHORS +++ b/AUTHORS @@ -243,6 +243,9 @@ nathanj439 Nikos Ntarmos FreeBSD total memory patch +Nikos Pylarinos + macOS support + norsetto fix SIGUSR1/SIGHUP segfault diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/cmake/Conky.cmake b/cmake/Conky.cmake index ac36c22d..31a77cb0 100644 --- a/cmake/Conky.cmake +++ b/cmake/Conky.cmake @@ -51,11 +51,15 @@ if(CMAKE_SYSTEM_NAME MATCHES "Haiku") set(OS_HAIKU true) endif(CMAKE_SYSTEM_NAME MATCHES "Haiku") +if(CMAKE_SYSTEM_NAME MATCHES "Darwin") + set(OS_DARWIN true) +endif(CMAKE_SYSTEM_NAME MATCHES "Darwin") + if(NOT OS_LINUX AND NOT OS_FREEBSD AND NOT OS_OPENBSD AND NOT OS_DRAGONFLY - AND NOT OS_SOLARIS AND NOT OS_HAIKU) + AND NOT OS_SOLARIS AND NOT OS_HAIKU AND NOT OS_DARWIN) message(FATAL_ERROR "Your platform, '${CMAKE_SYSTEM_NAME}', is not currently supported. Patches are welcome.") endif(NOT OS_LINUX AND NOT OS_FREEBSD AND NOT OS_OPENBSD AND NOT OS_DRAGONFLY - AND NOT OS_SOLARIS AND NOT OS_HAIKU) + AND NOT OS_SOLARIS AND NOT OS_HAIKU AND NOT OS_DARWIN) include(FindThreads) find_package(Threads) @@ -63,9 +67,15 @@ find_package(Threads) set(conky_libs ${CMAKE_THREAD_LIBS_INIT}) set(conky_includes ${CMAKE_BINARY_DIR}) -add_definitions(-D_LARGEFILE64_SOURCE -D_POSIX_C_SOURCE=200809L) # Standard definitions -set(CMAKE_REQUIRED_DEFINITIONS - "${CMAKE_REQUIRED_DEFINITIONS} -D_LARGEFILE64_SOURCE -D_POSIX_C_SOURCE=200809L") +# +# On Darwin _POSIX_C_SOURCE must be >= __DARWIN_C_FULL for asprintf to be enabled! +# Thus disable this and _LARGEFILE64_SOURCE isnt needed, it is already used on macOS. +# +if(NOT OS_DARWIN) + add_definitions(-D_LARGEFILE64_SOURCE -D_POSIX_C_SOURCE=200809L) # Standard definitions + set(CMAKE_REQUIRED_DEFINITIONS + "${CMAKE_REQUIRED_DEFINITIONS} -D_LARGEFILE64_SOURCE -D_POSIX_C_SOURCE=200809L") +endif(NOT OS_DARWIN) if(OS_DRAGONFLY) set(conky_libs ${conky_libs} -L/usr/pkg/lib) diff --git a/cmake/ConkyPlatformChecks.cmake b/cmake/ConkyPlatformChecks.cmake index ce5c109b..30dda7e6 100644 --- a/cmake/ConkyPlatformChecks.cmake +++ b/cmake/ConkyPlatformChecks.cmake @@ -36,11 +36,20 @@ check_function_exists(strndup HAVE_STRNDUP) check_symbol_exists(pipe2 "unistd.h" HAVE_PIPE2) check_symbol_exists(O_CLOEXEC "fcntl.h" HAVE_O_CLOEXEC) -check_symbol_exists(statfs64 "sys/statfs.h" HAVE_STATFS64) + +if(CMAKE_SYSTEM_NAME MATCHES "Darwin") + check_symbol_exists(statfs64 "sys/mount.h" HAVE_STATFS64) +else(CMAKE_SYSTEM_NAME MATCHES "Darwin") + check_symbol_exists(statfs64 "sys/statfs.h" HAVE_STATFS64) +endif(CMAKE_SYSTEM_NAME MATCHES "Darwin") AC_SEARCH_LIBS(clock_gettime "time.h" CLOCK_GETTIME_LIB "rt") if(NOT DEFINED CLOCK_GETTIME_LIB) - message(FATAL_ERROR "clock_gettime not found.") + if(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin") + message(FATAL_ERROR "clock_gettime not found.") + endif(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin") +else(NOT DEFINED CLOCK_GETTIME_LIB) + set(HAVE_CLOCK_GETTIME 1) endif(NOT DEFINED CLOCK_GETTIME_LIB) set(conky_libs ${conky_libs} ${CLOCK_GETTIME_LIB}) @@ -80,11 +89,15 @@ if(CMAKE_SYSTEM_NAME MATCHES "Haiku") set(conky_libs ${conky_libs} -lnetwork -lintl) endif(CMAKE_SYSTEM_NAME MATCHES "Haiku") +if(CMAKE_SYSTEM_NAME MATCHES "Darwin") + set(OS_DARWIN true) +endif(CMAKE_SYSTEM_NAME MATCHES "Darwin") + if(NOT OS_LINUX AND NOT OS_FREEBSD AND NOT OS_OPENBSD AND NOT OS_DRAGONFLY - AND NOT OS_SOLARIS AND NOT OS_HAIKU) + AND NOT OS_SOLARIS AND NOT OS_HAIKU AND NOT OS_DARWIN) message(FATAL_ERROR "Your platform, '${CMAKE_SYSTEM_NAME}', is not currently supported. Patches are welcome.") endif(NOT OS_LINUX AND NOT OS_FREEBSD AND NOT OS_OPENBSD AND NOT OS_DRAGONFLY - AND NOT OS_SOLARIS AND NOT OS_HAIKU) + AND NOT OS_SOLARIS AND NOT OS_HAIKU AND NOT OS_DARWIN) # Check for soundcard header if(OS_LINUX) @@ -100,6 +113,14 @@ if(BUILD_I18N AND OS_DRAGONFLY) set(conky_libs ${conky_libs} -lintl) endif(BUILD_I18N AND OS_DRAGONFLY) +if(BUILD_I18N AND OS_DARWIN) + set(conky_libs ${conky_libs} -lintl) +endif(BUILD_I18N AND OS_DARWIN) + +if(BUILD_NCURSES AND OS_DARWIN) + set(conky_libs ${conky_libs} -lncurses) +endif(BUILD_NCURSES AND OS_DARWIN) + if(BUILD_MATH) set(conky_libs ${conky_libs} -lm) endif(BUILD_MATH) diff --git a/cmake/config.h.in b/cmake/config.h.in index 094fe792..8bd09725 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -40,6 +40,8 @@ #cmakedefine HAVE_PIPE2 1 #cmakedefine HAVE_O_CLOEXEC 1 +#cmakedefine HAVE_CLOCK_GETTIME 1 + #cmakedefine BUILD_X11 1 #cmakedefine OWN_WINDOW 1 diff --git a/doc/variables.xml b/doc/variables.xml index 1615ec00..4603ab65 100644 --- a/doc/variables.xml +++ b/doc/variables.xml @@ -3744,6 +3744,41 @@ are supported, mbox type will return -1. + + + + + + + + Prints info regarding System Integrity Protection (SIP) on macOS. + + Specifically, prints SIP status (enabled / disabled) if no switch is + provided OR status of specific SIP feature if a switch is provided. + Below are the allowed switches: (each switch is a char) + SWITCH-----------------------RESULT------------------------------- + 0 allows apple-internal? YES/NO + 1 allows untrusted-kexts? YES/NO + 2 allows task-for-pid? YES/NO + 3 allows unrestricted-fs? YES/NO + 4 allows kernel-debugger? YES/NO + 5 allows unrestricted-dtrace? YES/NO + 6 allows unrestricted-nvram? YES/NO + 7 allows device-configuration? YES/NO + 8 allows any-recovery-os? YES/NO + 9 allows user-approved-kexts? YES/NO + a uses unsupported configuration? + If yes, prints "unsupported configuration, beware!" + Else, prints "configuration is ok". + ------------------------------------------------------------------ + EXAMPLE: + conky -t '${sip_status}' # print SIP status + conky -t '${sip_status 0}' # print allows apple-internal? Yes or No? + + NOTES: exists only for macOS version of conky and works on any macOS + version (even the ones prior El Capitan where SIP was first introduced). + + diff --git a/extras/nano/conky.nanorc b/extras/nano/conky.nanorc index b17bf29a..0e88235b 100644 --- a/extras/nano/conky.nanorc +++ b/extras/nano/conky.nanorc @@ -11,7 +11,7 @@ color green "\<(alignment|append_file|background|border_inner_margin|border_oute color yellow "\<(above|below|bottom_left|bottom_right|bottom_middle|desktop|dock|no|none|normal|override|skip_pager|skip_taskbar|sticky|top_left|top_right|top_middle|middle_left|middle_right|middle_middle|undecorated|yes)\>" ## Variables -color brightblue "\<(acpiacadapter|acpifan|acpitemp|addr|addrs|alignc|alignr|apcupsd|apcupsd_cable|apcupsd_charge|apcupsd_lastxfer|apcupsd_linev|apcupsd_load|apcupsd_loadbar|apcupsd_loadgauge|apcupsd_loadgraph|apcupsd_model|apcupsd_name|apcupsd_status|apcupsd_temp|apcupsd_timeleft|apcupsd_upsmode|apm_adapter|apm_battery_life|apm_battery_time|audacious_bar|audacious_bitrate|audacious_channels|audacious_filename|audacious_frequency|audacious_length|audacious_length_seconds|audacious_main_volume|audacious_playlist_length|audacious_playlist_position|audacious_position|audacious_position_seconds|audacious_status|audacious_title|battery|battery_bar|battery_percent|battery_short|battery_time|blink|bmpx_album|bmpx_artist|bmpx_bitrate|bmpx_title|bmpx_track|bmpx_uri|buffers|cached|cmdline_to_pid|color|color0|color1|color2|color3|color4|color5|color6|color7|color8|color9|combine|conky_build_arch|conky_build_date|conky_version|cpu|cpubar|cpugauge|cpugraph|curl|desktop|desktop_name|desktop_number|disk_protect|diskio|diskio_read|diskio_write|diskiograph|diskiograph_read|diskiograph_write|distribution|downspeed|downspeedf|downspeedgraph|draft_mails|else|endif|entropy_avail|entropy_bar|entropy_perc|entropy_poolsize|eval|eve|exec|execbar|execgauge|execgraph|execi|execibar|execigauge|execigraph|execp|execpi|flagged_mails|font|format_time|forwarded_mails|freq|freq_g|fs_bar|fs_bar_free|fs_free|fs_free_perc|fs_size|fs_type|fs_used|fs_used_perc|goto|gw_iface|gw_ip|hddtemp|head|hr|hwmon|i2c|i8k_ac_status|i8k_bios|i8k_buttons_status|i8k_cpu_temp|i8k_left_fan_rpm|i8k_left_fan_status|i8k_right_fan_rpm|i8k_right_fan_status|i8k_serial|i8k_version|ibm_brightness|ibm_fan|ibm_temps|ibm_volume|ical|iconv_start|iconv_stop|if_empty|if_existing|if_gw|if_match|if_mixer_mute|if_mounted|if_mpd_playing|if_running|if_smapi_bat_installed|if_up|if_updatenr|if_pa_sink_muted|if_xmms2_connected|image|imap_messages|imap_unseen|ioscheduler|irc|journal|kernel|laptop_mode|lines|loadavg|loadgraph|lua|lua_bar|lua_gauge|lua_graph|lua_parse|machine|mails|mboxscan|mem|memwithbuffers|membar|memwithbuffersbar|memeasyfree|memfree|memgauge|memgraph|memmax|memperc|mixer|mixerbar|mixerl|mixerlbar|mixerr|mixerrbar|moc_album|moc_artist|moc_bitrate|moc_curtime|moc_file|moc_rate|moc_song|moc_state|moc_timeleft|moc_title|moc_totaltime|monitor|monitor_number|mpd_album|mpd_artist|mpd_bar|mpd_bitrate|mpd_elapsed|mpd_file|mpd_length|mpd_name|mpd_percent|mpd_random|mpd_repeat|mpd_smart|mpd_status|mpd_title|mpd_track|mpd_vol|mysql|nameserver|new_mails|nodename|nodename_short|no_update|nvidia|obsd_product|obsd_sensors_fan|obsd_sensors_temp|obsd_sensors_volt|obsd_vendor|offset|outlinecolor|pa_sink_volume|pa_sink_volumebar|pa_sink_description|pa_card_name pa_card_active_profile|pb_battery|pid_chroot|pid_cmdline|pid_cwd|pid_environ|pid_environ_list|pid_exe|pid_nice|pid_openfiles|pid_parent|pid_priority|pid_state|pid_state_short|pid_stderr|pid_stdin|pid_stdout|pid_threads|pid_thread_list|pid_time_kernelmode|pid_time_usermode|pid_time|pid_uid|pid_euid|pid_suid|pid_fsuid|pid_gid|pid_egid|pid_sgid|pid_fsgid|pid_read|pid_vmpeak|pid_vmsize|pid_vmlck|pid_vmhwm|pid_vmrss|pid_vmdata|pid_vmstk|pid_vmexe|pid_vmlib|pid_vmpte|pid_write|platform|pop3_unseen|pop3_used|processes|read_tcp|read_udp|replied_mails|rss|running_processes|running_threads|scroll|seen_mails|shadecolor|smapi|smapi_bat_bar|smapi_bat_perc|smapi_bat_power|smapi_bat_temp|sony_fanspeed|stippled_hr|stock|swap|swapbar|swapfree|swapmax|swapperc|sysname|tab|tail|tcp_ping|tcp_portmon|template0|template1|template2|template3|template4|template5|template6|template7|template8|template9|texeci|texecpi|threads|time|to_bytes|top|top_io|top_mem|top_time|totaldown|totalup|trashed_mails|tztime|gid_name|uid_name|unflagged_mails|unforwarded_mails|unreplied_mails|unseen_mails|updates|upspeed|upspeedf|upspeedgraph|uptime|uptime_short|user_names|user_number|user_terms|user_times|user_time|utime|voffset|voltage_mv|voltage_v|weather|wireless_ap|wireless_bitrate|wireless_essid|wireless_link_bar|wireless_link_qual|wireless_link_qual_max|wireless_link_qual_perc|wireless_mode|words|xmms2_album|xmms2_artist|xmms2_bar|xmms2_bitrate|xmms2_comment|xmms2_date|xmms2_duration|xmms2_elapsed|xmms2_genre|xmms2_id|xmms2_percent|xmms2_playlist|xmms2_size|xmms2_smart|xmms2_status|xmms2_timesplayed|xmms2_title|xmms2_tracknr|xmms2_url)\>" +color brightblue "\<(acpiacadapter|acpifan|acpitemp|addr|addrs|alignc|alignr|apcupsd|apcupsd_cable|apcupsd_charge|apcupsd_lastxfer|apcupsd_linev|apcupsd_load|apcupsd_loadbar|apcupsd_loadgauge|apcupsd_loadgraph|apcupsd_model|apcupsd_name|apcupsd_status|apcupsd_temp|apcupsd_timeleft|apcupsd_upsmode|apm_adapter|apm_battery_life|apm_battery_time|audacious_bar|audacious_bitrate|audacious_channels|audacious_filename|audacious_frequency|audacious_length|audacious_length_seconds|audacious_main_volume|audacious_playlist_length|audacious_playlist_position|audacious_position|audacious_position_seconds|audacious_status|audacious_title|battery|battery_bar|battery_percent|battery_short|battery_time|blink|bmpx_album|bmpx_artist|bmpx_bitrate|bmpx_title|bmpx_track|bmpx_uri|buffers|cached|cmdline_to_pid|color|color0|color1|color2|color3|color4|color5|color6|color7|color8|color9|combine|conky_build_arch|conky_build_date|conky_version|cpu|cpubar|cpugauge|cpugraph|curl|desktop|desktop_name|desktop_number|disk_protect|diskio|diskio_read|diskio_write|diskiograph|diskiograph_read|diskiograph_write|distribution|downspeed|downspeedf|downspeedgraph|draft_mails|else|endif|entropy_avail|entropy_bar|entropy_perc|entropy_poolsize|eval|eve|exec|execbar|execgauge|execgraph|execi|execibar|execigauge|execigraph|execp|execpi|flagged_mails|font|format_time|forwarded_mails|freq|freq_g|fs_bar|fs_bar_free|fs_free|fs_free_perc|fs_size|fs_type|fs_used|fs_used_perc|goto|gw_iface|gw_ip|hddtemp|head|hr|hwmon|i2c|i8k_ac_status|i8k_bios|i8k_buttons_status|i8k_cpu_temp|i8k_left_fan_rpm|i8k_left_fan_status|i8k_right_fan_rpm|i8k_right_fan_status|i8k_serial|i8k_version|ibm_brightness|ibm_fan|ibm_temps|ibm_volume|ical|iconv_start|iconv_stop|if_empty|if_existing|if_gw|if_match|if_mixer_mute|if_mounted|if_mpd_playing|if_running|if_smapi_bat_installed|if_up|if_updatenr|if_pa_sink_muted|if_xmms2_connected|image|imap_messages|imap_unseen|ioscheduler|irc|journal|kernel|laptop_mode|lines|loadavg|loadgraph|lua|lua_bar|lua_gauge|lua_graph|lua_parse|machine|mails|mboxscan|mem|memwithbuffers|membar|memwithbuffersbar|memeasyfree|memfree|memgauge|memgraph|memmax|memperc|mixer|mixerbar|mixerl|mixerlbar|mixerr|mixerrbar|moc_album|moc_artist|moc_bitrate|moc_curtime|moc_file|moc_rate|moc_song|moc_state|moc_timeleft|moc_title|moc_totaltime|monitor|monitor_number|mpd_album|mpd_artist|mpd_bar|mpd_bitrate|mpd_elapsed|mpd_file|mpd_length|mpd_name|mpd_percent|mpd_random|mpd_repeat|mpd_smart|mpd_status|mpd_title|mpd_track|mpd_vol|mysql|nameserver|new_mails|nodename|nodename_short|no_update|nvidia|obsd_product|obsd_sensors_fan|obsd_sensors_temp|obsd_sensors_volt|obsd_vendor|offset|outlinecolor|pa_sink_volume|pa_sink_volumebar|pa_sink_description|pa_card_name pa_card_active_profile|pb_battery|pid_chroot|pid_cmdline|pid_cwd|pid_environ|pid_environ_list|pid_exe|pid_nice|pid_openfiles|pid_parent|pid_priority|pid_state|pid_state_short|pid_stderr|pid_stdin|pid_stdout|pid_threads|pid_thread_list|pid_time_kernelmode|pid_time_usermode|pid_time|pid_uid|pid_euid|pid_suid|pid_fsuid|pid_gid|pid_egid|pid_sgid|pid_fsgid|pid_read|pid_vmpeak|pid_vmsize|pid_vmlck|pid_vmhwm|pid_vmrss|pid_vmdata|pid_vmstk|pid_vmexe|pid_vmlib|pid_vmpte|pid_write|platform|pop3_unseen|pop3_used|processes|read_tcp|read_udp|replied_mails|rss|running_processes|running_threads|scroll|seen_mails|shadecolor|sip_status|smapi|smapi_bat_bar|smapi_bat_perc|smapi_bat_power|smapi_bat_temp|sony_fanspeed|stippled_hr|stock|swap|swapbar|swapfree|swapmax|swapperc|sysname|tab|tail|tcp_ping|tcp_portmon|template0|template1|template2|template3|template4|template5|template6|template7|template8|template9|texeci|texecpi|threads|time|to_bytes|top|top_io|top_mem|top_time|totaldown|totalup|trashed_mails|tztime|gid_name|uid_name|unflagged_mails|unforwarded_mails|unreplied_mails|unseen_mails|updates|upspeed|upspeedf|upspeedgraph|uptime|uptime_short|user_names|user_number|user_terms|user_times|user_time|utime|voffset|voltage_mv|voltage_v|weather|wireless_ap|wireless_bitrate|wireless_essid|wireless_link_bar|wireless_link_qual|wireless_link_qual_max|wireless_link_qual_perc|wireless_mode|words|xmms2_album|xmms2_artist|xmms2_bar|xmms2_bitrate|xmms2_comment|xmms2_date|xmms2_duration|xmms2_elapsed|xmms2_genre|xmms2_id|xmms2_percent|xmms2_playlist|xmms2_size|xmms2_smart|xmms2_status|xmms2_timesplayed|xmms2_title|xmms2_tracknr|xmms2_url)\>" color brightblue "\$\{?[0-9A-Z_!@#$*?-]+\}?" color cyan "(\{|\}|\(|\)|\;|\]|\[|`|\\|\$|<|>|!|=|&|\|)" diff --git a/extras/vim/syntax/conkyrc.vim b/extras/vim/syntax/conkyrc.vim index 93ec4cd0..3d5c1beb 100644 --- a/extras/vim/syntax/conkyrc.vim +++ b/extras/vim/syntax/conkyrc.vim @@ -50,7 +50,7 @@ syn region ConkyrcVar start=/\$\w\@=/ end=/\W\@=\|$/ contained contains=ConkyrcV syn match ConkyrcVarStuff /{\@<=/ms=s contained nextgroup=ConkyrcVarName -syn keyword ConkyrcVarName contained nextgroup=ConkyrcNumber,ConkyrcColour skipwhite acpiacadapter acpifan acpitemp addr addrs alignc alignr apcupsd apcupsd_cable apcupsd_charge apcupsd_lastxfer apcupsd_linev apcupsd_load apcupsd_loadbar apcupsd_loadgauge apcupsd_loadgraph apcupsd_model apcupsd_name apcupsd_status apcupsd_temp apcupsd_timeleft apcupsd_upsmode apm_adapter apm_battery_life apm_battery_time audacious_bar audacious_bitrate audacious_channels audacious_filename audacious_frequency audacious_length audacious_length_seconds audacious_main_volume audacious_playlist_length audacious_playlist_position audacious_position audacious_position_seconds audacious_status audacious_title battery battery_bar battery_percent battery_short battery_time blink bmpx_album bmpx_artist bmpx_bitrate bmpx_title bmpx_track bmpx_uri buffers cached cmdline_to_pid color color0 color1 color2 color3 color4 color5 color6 color7 color8 color9 combine conky_build_arch conky_build_date conky_version cpu cpubar cpugauge cpugraph curl desktop desktop_name desktop_number disk_protect diskio diskio_read diskio_write diskiograph diskiograph_read diskiograph_write distribution downspeed downspeedf downspeedgraph draft_mails else endif entropy_avail entropy_bar entropy_perc entropy_poolsize eval eve exec execbar execgauge execgraph execi execibar execigauge execigraph execp execpi flagged_mails font format_time forwarded_mails freq freq_g fs_bar fs_bar_free fs_free fs_free_perc fs_size fs_type fs_used fs_used_perc goto gw_iface gw_ip hddtemp head hr hwmon i2c i8k_ac_status i8k_bios i8k_buttons_status i8k_cpu_temp i8k_left_fan_rpm i8k_left_fan_status i8k_right_fan_rpm i8k_right_fan_status i8k_serial i8k_version ibm_brightness ibm_fan ibm_temps ibm_volume ical iconv_start iconv_stop if_pa_sink_muted if_empty if_existing if_gw if_match if_mixer_mute if_mounted if_mpd_playing if_running if_smapi_bat_installed if_up if_updatenr if_xmms2_connected image imap_messages imap_unseen ioscheduler irc journal kernel laptop_mode lines loadavg loadgraph lua lua_bar lua_gauge lua_graph lua_parse machine mails mboxscan mem memwithbuffers membar memwithbuffersbar memeasyfree memfree memgauge memgraph memmax memperc mixer mixerbar mixerl mixerlbar mixerr mixerrbar moc_album moc_artist moc_bitrate moc_curtime moc_file moc_rate moc_song moc_state moc_timeleft moc_title moc_totaltime monitor monitor_number mpd_album mpd_artist mpd_bar mpd_bitrate mpd_elapsed mpd_file mpd_length mpd_name mpd_percent mpd_random mpd_repeat mpd_smart mpd_status mpd_title mpd_track mpd_vol mysql nameserver new_mails nodename nodename_short no_update nvidia obsd_product obsd_sensors_fan obsd_sensors_temp obsd_sensors_volt obsd_vendor offset outlinecolor pa_sink_volume pa_sink_volumebar pa_sink_description pa_card_name pa_card_active_profile pb_battery pid_chroot pid_cmdline pid_cwd pid_environ pid_environ_list pid_exe pid_nice pid_openfiles pid_parent pid_priority pid_state pid_state_short pid_stderr pid_stdin pid_stdout pid_threads pid_thread_list pid_time_kernelmode pid_time_usermode pid_time pid_uid pid_euid pid_suid pid_fsuid pid_gid pid_egid pid_sgid pid_fsgid pid_read pid_vmpeak pid_vmsize pid_vmlck pid_vmhwm pid_vmrss pid_vmdata pid_vmstk pid_vmexe pid_vmlib pid_vmpte pid_write platform pop3_unseen pop3_used processes read_tcp read_udp replied_mails rss running_processes running_threads scroll seen_mails shadecolor smapi smapi_bat_bar smapi_bat_perc smapi_bat_power smapi_bat_temp sony_fanspeed stippled_hr stock swap swapbar swapfree swapmax swapperc sysname tab tail tcp_ping tcp_portmon template0 template1 template2 template3 template4 template5 template6 template7 template8 template9 texeci texecpi threads time to_bytes top top_io top_mem top_time totaldown totalup trashed_mails tztime gid_name uid_name unflagged_mails unforwarded_mails unreplied_mails unseen_mails updates upspeed upspeedf upspeedgraph uptime uptime_short user_names user_number user_terms user_times user_time utime voffset voltage_mv voltage_v weather wireless_ap wireless_bitrate wireless_essid wireless_link_bar wireless_link_qual wireless_link_qual_max wireless_link_qual_perc wireless_mode words xmms2_album xmms2_artist xmms2_bar xmms2_bitrate xmms2_comment xmms2_date xmms2_duration xmms2_elapsed xmms2_genre xmms2_id xmms2_percent xmms2_playlist xmms2_size xmms2_smart xmms2_status xmms2_timesplayed xmms2_title xmms2_tracknr xmms2_url +syn keyword ConkyrcVarName contained nextgroup=ConkyrcNumber,ConkyrcColour skipwhite acpiacadapter acpifan acpitemp addr addrs alignc alignr apcupsd apcupsd_cable apcupsd_charge apcupsd_lastxfer apcupsd_linev apcupsd_load apcupsd_loadbar apcupsd_loadgauge apcupsd_loadgraph apcupsd_model apcupsd_name apcupsd_status apcupsd_temp apcupsd_timeleft apcupsd_upsmode apm_adapter apm_battery_life apm_battery_time audacious_bar audacious_bitrate audacious_channels audacious_filename audacious_frequency audacious_length audacious_length_seconds audacious_main_volume audacious_playlist_length audacious_playlist_position audacious_position audacious_position_seconds audacious_status audacious_title battery battery_bar battery_percent battery_short battery_time blink bmpx_album bmpx_artist bmpx_bitrate bmpx_title bmpx_track bmpx_uri buffers cached cmdline_to_pid color color0 color1 color2 color3 color4 color5 color6 color7 color8 color9 combine conky_build_arch conky_build_date conky_version cpu cpubar cpugauge cpugraph curl desktop desktop_name desktop_number disk_protect diskio diskio_read diskio_write diskiograph diskiograph_read diskiograph_write distribution downspeed downspeedf downspeedgraph draft_mails else endif entropy_avail entropy_bar entropy_perc entropy_poolsize eval eve exec execbar execgauge execgraph execi execibar execigauge execigraph execp execpi flagged_mails font format_time forwarded_mails freq freq_g fs_bar fs_bar_free fs_free fs_free_perc fs_size fs_type fs_used fs_used_perc goto gw_iface gw_ip hddtemp head hr hwmon i2c i8k_ac_status i8k_bios i8k_buttons_status i8k_cpu_temp i8k_left_fan_rpm i8k_left_fan_status i8k_right_fan_rpm i8k_right_fan_status i8k_serial i8k_version ibm_brightness ibm_fan ibm_temps ibm_volume ical iconv_start iconv_stop if_pa_sink_muted if_empty if_existing if_gw if_match if_mixer_mute if_mounted if_mpd_playing if_running if_smapi_bat_installed if_up if_updatenr if_xmms2_connected image imap_messages imap_unseen ioscheduler irc journal kernel laptop_mode lines loadavg loadgraph lua lua_bar lua_gauge lua_graph lua_parse machine mails mboxscan mem memwithbuffers membar memwithbuffersbar memeasyfree memfree memgauge memgraph memmax memperc mixer mixerbar mixerl mixerlbar mixerr mixerrbar moc_album moc_artist moc_bitrate moc_curtime moc_file moc_rate moc_song moc_state moc_timeleft moc_title moc_totaltime monitor monitor_number mpd_album mpd_artist mpd_bar mpd_bitrate mpd_elapsed mpd_file mpd_length mpd_name mpd_percent mpd_random mpd_repeat mpd_smart mpd_status mpd_title mpd_track mpd_vol mysql nameserver new_mails nodename nodename_short no_update nvidia obsd_product obsd_sensors_fan obsd_sensors_temp obsd_sensors_volt obsd_vendor offset outlinecolor pa_sink_volume pa_sink_volumebar pa_sink_description pa_card_name pa_card_active_profile pb_battery pid_chroot pid_cmdline pid_cwd pid_environ pid_environ_list pid_exe pid_nice pid_openfiles pid_parent pid_priority pid_state pid_state_short pid_stderr pid_stdin pid_stdout pid_threads pid_thread_list pid_time_kernelmode pid_time_usermode pid_time pid_uid pid_euid pid_suid pid_fsuid pid_gid pid_egid pid_sgid pid_fsgid pid_read pid_vmpeak pid_vmsize pid_vmlck pid_vmhwm pid_vmrss pid_vmdata pid_vmstk pid_vmexe pid_vmlib pid_vmpte pid_write platform pop3_unseen pop3_used processes read_tcp read_udp replied_mails rss running_processes running_threads scroll seen_mails shadecolor sip_status smapi smapi_bat_bar smapi_bat_perc smapi_bat_power smapi_bat_temp sony_fanspeed stippled_hr stock swap swapbar swapfree swapmax swapperc sysname tab tail tcp_ping tcp_portmon template0 template1 template2 template3 template4 template5 template6 template7 template8 template9 texeci texecpi threads time to_bytes top top_io top_mem top_time totaldown totalup trashed_mails tztime gid_name uid_name unflagged_mails unforwarded_mails unreplied_mails unseen_mails updates upspeed upspeedf upspeedgraph uptime uptime_short user_names user_number user_terms user_times user_time utime voffset voltage_mv voltage_v weather wireless_ap wireless_bitrate wireless_essid wireless_link_bar wireless_link_qual wireless_link_qual_max wireless_link_qual_perc wireless_mode words xmms2_album xmms2_artist xmms2_bar xmms2_bitrate xmms2_comment xmms2_date xmms2_duration xmms2_elapsed xmms2_genre xmms2_id xmms2_percent xmms2_playlist xmms2_size xmms2_smart xmms2_status xmms2_timesplayed xmms2_title xmms2_tracknr xmms2_url hi def link ConkyrcComment Comment hi def link ConkyrcSetting Keyword diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b83c851e..6a5b45df 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -80,6 +80,11 @@ if(OS_HAIKU) set(optional_sources ${optional_sources} ${haiku}) endif(OS_HAIKU) +if(OS_DARWIN) + set(darwin darwin.cc) + set(optional_sources ${optional_sources} ${darwin}) +endif(OS_DARWIN) + # Optional sources if(HAVE_SOME_SOUNDCARD_H) set(mixer mixer.cc) diff --git a/src/common.cc b/src/common.cc index b5cce1c5..37fddf3e 100644 --- a/src/common.cc +++ b/src/common.cc @@ -59,6 +59,8 @@ #include "dragonfly.h" #elif defined(__OpenBSD__) #include "openbsd.h" +#elif defined(__APPLE__) && defined(__MACH__) +#include "darwin.h" // strings.h #endif #include "update-cb.hh" diff --git a/src/conky.h b/src/conky.h index 9c7e4e13..f981aafb 100644 --- a/src/conky.h +++ b/src/conky.h @@ -218,6 +218,30 @@ struct information { #endif /* BUILD_X11 */ short kflags; /* kernel settings, see enum KFLAG */ + +#if defined(__APPLE__) && defined(__MACH__) + /* System Integrity Protection related */ + struct csr_config_flags { + bool csr_allow_untrusted_kexts; + bool csr_allow_unrestricted_fs; + bool csr_allow_task_for_pid; + bool csr_allow_kernel_debugger; + bool csr_allow_apple_internal; + bool csr_allow_unrestricted_dtrace; + bool csr_allow_unrestricted_nvram; + bool csr_allow_device_configuration; + bool csr_allow_any_recovery_os; + bool csr_allow_user_approved_kexts; + }; + + /* SIP typedefs */ + typedef csr_config_flags csr_config_flags_t; + typedef uint32_t csr_config_t; + + /* SIP variables */ + csr_config_t csr_config; + csr_config_flags_t csr_config_flags; +#endif /* defined(__APPLE__) && defined(__MACH__) */ }; class music_player_interval_setting: public conky::simple_config_setting { diff --git a/src/core.cc b/src/core.cc index ded49eff..91924b27 100644 --- a/src/core.cc +++ b/src/core.cc @@ -115,6 +115,8 @@ #include "dragonfly.h" #elif defined(__OpenBSD__) #include "openbsd.h" +#elif defined(__APPLE__) && defined(__MACH__) +#include "darwin.h" #endif #include @@ -542,7 +544,7 @@ struct text_object *construct_text_object(char *s, const char *arg, } obj->callbacks.print = get_powerbook_batt_info; #endif /* __linux__ */ -#if (defined(__FreeBSD__) || defined(__linux__) || defined(__DragonFly__)) +#if (defined(__FreeBSD__) || defined(__linux__) || defined(__DragonFly__) || (defined(__APPLE__) && defined(__MACH__))) END OBJ_IF_ARG(if_up, 0, "if_up needs an argument") parse_if_up_arg(obj, arg); obj->callbacks.iftest = &interface_up; @@ -954,6 +956,17 @@ struct text_object *construct_text_object(char *s, const char *arg, obj->data.s = strndup(arg, text_buffer_size.get(*state)); obj->callbacks.iftest = &if_running_iftest; obj->callbacks.free = &gen_free_opaque; +#elif defined(__APPLE__) && defined(__MACH__) + END OBJ_IF_ARG(if_mounted, 0, "if_mounted needs an argument") + obj->data.s = strndup(arg, text_buffer_size.get(*state)); + obj->callbacks.iftest = &check_mount; + obj->callbacks.free = &gen_free_opaque; + + /* System Integrity Protection */ + END OBJ(sip_status, &get_sip_status) + obj->data.s = strndup(arg ? arg : "", text_buffer_size.get(*state)); + obj->callbacks.print = &print_sip_status; + obj->callbacks.free = &gen_free_opaque; #else END OBJ_IF_ARG(if_running, 0, "if_running needs an argument") char buf[text_buffer_size.get(*state)]; @@ -1251,6 +1264,13 @@ struct text_object *construct_text_object(char *s, const char *arg, #if defined(__DragonFly__) END OBJ(running_processes, &update_top) obj->callbacks.print = &print_running_processes; +#elif (defined(__APPLE__) && defined(__MACH__)) + END OBJ(running_processes, &update_running_processes) + obj->callbacks.print = &print_running_processes; + END OBJ(threads, &update_threads) + obj->callbacks.print = &print_threads; + END OBJ(running_threads, &update_running_threads) + obj->callbacks.print = &print_running_threads; #else END OBJ(running_processes, &update_running_processes) obj->callbacks.print = &print_running_processes; diff --git a/src/darwin.cc b/src/darwin.cc new file mode 100644 index 00000000..13b0d555 --- /dev/null +++ b/src/darwin.cc @@ -0,0 +1,1480 @@ +/* + * Conky, a system monitor, based on torsmo + * + * Any original torsmo code is licensed under the BSD license + * + * All code written since the fork of torsmo is licensed under the GPL + * + * Please see COPYING for details + * + * Copyright (c) 2018, npyl + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/* + *********************************************************************************************** + * + * darwin.cc + * Nickolas Pylarinos + * + * ~ To mrt and vggol ~ + * + *********************************************************************************************** + * + * Code for SIP taken from Pike R. Alpha's csrstat tool https://github.com/Piker-Alpha/csrstat + * csrstat version 1.8 ( works for OS up to High Sierra ) + * + * My patches: + * made csr_get_active_config weak link and added check for finding if it is available. + * patched the _csr_check function to return the bool bit instead. + */ + +/* + * Apologies for the code style... + * In my eyes it feels better to have + * different styles at some specific places... :) + */ + +#include "darwin.h" +#include "conky.h" // for struct info + +#include + +#include +#include // statfs +#include + +#include +#include +#include +#include +#include + +#include // update_total_processes + +#include // get_top_info +#include // get_top_info +#include "top.h" // get_top_info + +#include // update_net_stats +#include "net_stat.h" // update_net_stats + +#include "darwin_sip.h" // sip status + +/* clock_gettime includes */ +#ifndef HAVE_CLOCK_GETTIME +#include +#include +#include +#include +#include +#endif + +/* debugging defines */ +#define DEBUG_MODE + +/* (E)nhanced printf */ +#ifdef DEBUG_MODE +#include +void eprintf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} +#else +#define eprintf(...) /* ... */ +#endif + +#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var)) + +/* + * used by calc_cpu_each() for get_top_info() + */ +static conky::simple_config_setting top_cpu_separate("top_cpu_separate", false, true); + +static int getsysctl(const char *name, void *ptr, size_t len) +{ + size_t nlen = len; + + if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { + return -1; + } + + if (nlen != len && errno == ENOMEM) { + return -1; + } + + return 0; +} + +/* + * clock_gettime is not implemented on versions prior to Sierra! + * code taken from https://github.com/lorrden/darwin-posix-rt/blob/master/clock_gettime.c + */ +#ifndef HAVE_CLOCK_GETTIME + +int clock_gettime(int clock_id, struct timespec *ts) +{ + mach_timespec_t mts; + static clock_serv_t rt_clock_serv = 0; + static clock_serv_t mono_clock_serv = 0; + + switch (clock_id) { + case CLOCK_REALTIME: + if (rt_clock_serv == 0) { + (void) host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &rt_clock_serv); + } + (void) clock_get_time(rt_clock_serv, &mts); + ts->tv_sec = mts.tv_sec; + ts->tv_nsec = mts.tv_nsec; + return 0; + case CLOCK_MONOTONIC: + if (mono_clock_serv == 0) { + (void) host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &mono_clock_serv); + } + (void) clock_get_time(mono_clock_serv, &mts); + ts->tv_sec = mts.tv_sec; + ts->tv_nsec = mts.tv_nsec; + return 0; + default: + errno = EINVAL; + return -1; + } +} +#endif /* ifndef HAVE_CLOCK_GETTIME */ + +/* + * helper_update_threads_processes() + * + * Helper function for update_threads() and update_running_threads() + * Uses mach API to get load info ( task_count, thread_count ) + * + */ +static void helper_update_threads_processes(void) +{ + static host_name_port_t machHost; + static processor_set_name_port_t processorSet = 0; + static bool machStuffInitialised = false; + + /* Set up our mach host and default processor set for later calls */ + if (!machStuffInitialised) + { + machHost = mach_host_self(); + processor_set_default(machHost, &processorSet); + + /* set this to true so we don't ever initialise stuff again */ + machStuffInitialised = true; + } + + /* get load info */ + struct processor_set_load_info loadInfo; + mach_msg_type_number_t count = PROCESSOR_SET_LOAD_INFO_COUNT; + kern_return_t err = processor_set_statistics(processorSet, PROCESSOR_SET_LOAD_INFO, + (processor_set_info_t)&loadInfo, &count); + + if (err != KERN_SUCCESS) + return; + + info.procs = loadInfo.task_count; + info.threads = loadInfo.thread_count; +} + +/* + * useful info about the cpu used by functions such as update_cpu_usage() and get_top_info() + */ +struct cpusample +{ + uint64_t totalUserTime; /* ticks of CPU in userspace */ + uint64_t totalSystemTime; /* ticks of CPU in kernelspace */ + uint64_t totalIdleTime; /* ticks in idleness */ + + uint64_t total; /* delta of current and previous */ + uint64_t current_total; /* total CPU ticks of current iteration */ + uint64_t previous_total; /* total CPU tick of previous iteration */ +}; + +/* + * Memory sample + */ +typedef struct memorysample +{ + vm_statistics64_data_t vm_stat; /* general VM information */ + uint64_t pages_stolen; /* # of stolen pages */ + vm_size_t pagesize; /* pagesize (in bytes) */ + boolean_t purgeable_is_valid; /* check if we have data for purgeable memory */ +} libtop_tsamp_t; + +/* + * get_cpu_sample() + * + * Gets systemTime, userTime and idleTime for CPU + * MenuMeters has been great inspiration for this function + */ +static void get_cpu_sample(struct cpusample *sample) +{ + host_name_port_t machHost; + natural_t processorCount; + processor_cpu_load_info_t processorTickInfo; + mach_msg_type_number_t processorInfoCount; + struct cpusample *samples = NULL; + + machHost = mach_host_self(); + + kern_return_t err = host_processor_info(machHost, PROCESSOR_CPU_LOAD_INFO, &processorCount, (processor_info_array_t *)&processorTickInfo, &processorInfoCount); + if (err != KERN_SUCCESS) + { + printf("host_statistics: %s\n", mach_error_string(err)); + return; + } + + /* + * allocate ncpus+1 cpusample structs (one foreach CPU) + * ** samples[0] is overal CPU usage + */ + samples = new struct cpusample[processorCount + 1]; + memset(samples, 0, sizeof(cpusample)*(processorCount+1)); + + /* + * start from samples[1] because samples[0] is overall CPU usage + */ + for (natural_t i = 1; i < processorCount + 1; i++) + { + samples[i].totalSystemTime = processorTickInfo[i-1].cpu_ticks[CPU_STATE_SYSTEM], + samples[i].totalUserTime = processorTickInfo[i-1].cpu_ticks[CPU_STATE_USER], + samples[i].totalIdleTime = processorTickInfo[i-1].cpu_ticks[CPU_STATE_IDLE]; + } + + /* + * sum up all totals + */ + for (natural_t i = 1; i < processorCount + 1; i++) + { + samples[0].totalSystemTime += samples[i].totalSystemTime; + samples[0].totalUserTime += samples[i].totalUserTime; + samples[0].totalIdleTime += samples[i].totalIdleTime; + } + + /* + * set the sample pointer + */ + sample->totalSystemTime = samples[0].totalSystemTime; + sample->totalUserTime = samples[0].totalUserTime; + sample->totalIdleTime = samples[0].totalIdleTime; + + /* + * Dealloc + */ + vm_deallocate(mach_task_self(), (vm_address_t)processorTickInfo, (vm_size_t)(processorInfoCount * sizeof(natural_t))); + delete[] samples; + + return; +} + +/* + * helper_get_proc_list() + * + * helper function that returns the count of processes + * and provides a list of kinfo_proc structs representing each. + * + * ERRORS: returns -1 if something failed + * + * ATTENTION: Do not forget to free the array once you are done with it, + * it is not freed automatically. + */ +static int helper_get_proc_list( struct kinfo_proc **p = NULL ) +{ + int err = 0; + size_t length = 0; + static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }; + + /* Call sysctl with a NULL buffer to get proper length */ + err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, NULL, &length, NULL, 0); + if (err) { + perror(NULL); + return (-1); + } + + /* Allocate buffer */ + *p = (kinfo_proc*)malloc(length); + if (!p) { + perror(NULL); + return (-1); + } + + /* Get the actual process list */ + err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, *p, &length, NULL, 0); + if (err) + { + perror(NULL); + return (-1); + } + + int proc_count = length / sizeof(struct kinfo_proc); + return proc_count; +} + +/*------------------------------------------------------------------------------------------------------------------------------------------------------------------- + * macOS Swapfiles Logic... + * + * o There is NO separate partition for swap storage ( unlike most Unix-based OSes ) --- Instead swap memory is stored in the currently used partition inside files + * + * o macOS can use ALL the available space on the used partition + * + * o Swap memory files are called swapfiles, stored inside /private/var/vm/ + * + * o Every swapfile has index number eg. swapfile0, swapfile1, ... + * + * o Anyone can change the location of the swapfiles by editing the plist: /System/Library/LaunchDaemons/com.apple.dynamic_pager.plist + * ( Though it seems like this is not supported by the dynamic_pager application as can be observed from the code: + * https://github.com/practicalswift/osx/blob/master/src/system_cmds/dynamic_pager.tproj/dynamic_pager.c ) + * o Every swapfile has size of 1GB + * + *------------------------------------------------------------------------------------------------------------------------------------------------------------------- + */ + +static int swapmode(unsigned long *retavail, unsigned long *retfree) +{ + /* + * COMPATIBILITY: Tiger+ + */ + + int swapMIB[] = { CTL_VM, 5 }; + struct xsw_usage swapUsage; + size_t swapUsageSize = sizeof(swapUsage); + memset(&swapUsage, 0, sizeof(swapUsage)); + if (sysctl(swapMIB, 2, &swapUsage, &swapUsageSize, NULL, 0) == 0) { + + *retfree = swapUsage.xsu_avail / 1024; + *retavail = swapUsage.xsu_total / 1024; + } else { + perror("sysctl"); + return (-1); + } + + return 1; +} + +void prepare_update(void) +{ + // in freebsd.cc this is empty so leaving it here too! +} + +int update_uptime(void) +{ + int mib[2] = { CTL_KERN, KERN_BOOTTIME }; + struct timeval boottime; + time_t now; + size_t size = sizeof(boottime); + + if ((sysctl(mib, 2, &boottime, &size, NULL, 0) != -1) + && (boottime.tv_sec != 0)) { + time(&now); + info.uptime = now - boottime.tv_sec; + } else { + fprintf(stderr, "could not get uptime\n"); + info.uptime = 0; + } + + return 0; +} + +/* + * check_mount + * + * Notes on macOS implementation: + * 1. path mustn't contain a '/' at the end! ( eg. /Volumes/MacOS/ is not correct but this is correct: /Volumes/MacOS ) + * 2. it works the same as the FreeBSD function + */ +int check_mount(struct text_object *obj) +{ + int num_mounts = 0; + struct statfs* mounts; + + if (!obj->data.s) + return 0; + + num_mounts = getmntinfo(&mounts, MNT_WAIT); + + if (num_mounts < 0) + { + NORM_ERR("could not get mounts using getmntinfo"); + return 0; + } + + for (int i = 0; i < num_mounts; i++) + if (strcmp(mounts[i].f_mntonname, obj->data.s) == 0) + { + return 1; + } + + return 0; +} + +/* + * required by update_pages_stolen(). + * Taken from apple's top. + * The code is intact. + */ +/* This is for . */ +static uint64_t +round_down_wired(uint64_t value) { + return (value & ~((128 * 1024 * 1024ULL) - 1)); +} + +/* + * must be called before libtop_tsamp_update_vm_stats() + * to calculate the pages_stolen variable. + * Taken from apple's top. + * The code is intact. + */ +/* This is for . */ +static void +update_pages_stolen(libtop_tsamp_t *tsamp) { + static int mib_reserved[CTL_MAXNAME]; + static int mib_unusable[CTL_MAXNAME]; + static int mib_other[CTL_MAXNAME]; + static size_t mib_reserved_len = 0; + static size_t mib_unusable_len = 0; + static size_t mib_other_len = 0; + int r; + + tsamp->pages_stolen = 0; + + /* This can be used for testing: */ + //tsamp->pages_stolen = (256 * 1024 * 1024ULL) / tsamp->pagesize; + + if(0 == mib_reserved_len) { + mib_reserved_len = CTL_MAXNAME; + + r = sysctlnametomib("machdep.memmap.Reserved", mib_reserved, + &mib_reserved_len); + + if(-1 == r) { + mib_reserved_len = 0; + return; + } + + mib_unusable_len = CTL_MAXNAME; + + r = sysctlnametomib("machdep.memmap.Unusable", mib_unusable, + &mib_unusable_len); + + if(-1 == r) { + mib_reserved_len = 0; + return; + } + + + mib_other_len = CTL_MAXNAME; + + r = sysctlnametomib("machdep.memmap.Other", mib_other, + &mib_other_len); + + if(-1 == r) { + mib_reserved_len = 0; + return; + } + } + + if(mib_reserved_len > 0 && mib_unusable_len > 0 && mib_other_len > 0) { + uint64_t reserved = 0, unusable = 0, other = 0; + size_t reserved_len; + size_t unusable_len; + size_t other_len; + + reserved_len = sizeof(reserved); + unusable_len = sizeof(unusable); + other_len = sizeof(other); + + /* These are all declared as QUAD/uint64_t sysctls in the kernel. */ + + if(-1 == sysctl(mib_reserved, mib_reserved_len, &reserved, + &reserved_len, NULL, 0)) { + return; + } + + if(-1 == sysctl(mib_unusable, mib_unusable_len, &unusable, + &unusable_len, NULL, 0)) { + return; + } + + if(-1 == sysctl(mib_other, mib_other_len, &other, + &other_len, NULL, 0)) { + return; + } + + if(reserved_len == sizeof(reserved) + && unusable_len == sizeof(unusable) + && other_len == sizeof(other)) { + uint64_t stolen = reserved + unusable + other; + uint64_t mb128 = 128 * 1024 * 1024ULL; + + if(stolen >= mb128) { + tsamp->pages_stolen = round_down_wired(stolen) / tsamp->pagesize; + } + } + } +} + +/** + * libtop_tsamp_update_vm_stats + * + * taken from apple's top (libtop.c) + * Changes for conky: + * - remove references to p_* and b_* named variables + * - remove reference to seq variable + * - libtop_port replaced with mach_host_self() + */ +static int +libtop_tsamp_update_vm_stats(libtop_tsamp_t* tsamp) { + kern_return_t kr; + + mach_msg_type_number_t count = sizeof(tsamp->vm_stat) / sizeof(natural_t); + kr = host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&tsamp->vm_stat, &count); + if (kr != KERN_SUCCESS) { + return kr; + } + + if (tsamp->pages_stolen > 0) { + tsamp->vm_stat.wire_count += tsamp->pages_stolen; + } + + // Check whether we got purgeable memory statistics + tsamp->purgeable_is_valid = (count == (sizeof(tsamp->vm_stat)/sizeof(natural_t))); + if (!tsamp->purgeable_is_valid) { + tsamp->vm_stat.purgeable_count = 0; + tsamp->vm_stat.purges = 0; + } + + return kr; +} + +/* + * helper function for update_meminfo() + * return physical memory in bytes + */ +uint64_t get_physical_memory(void) +{ + int mib[2] = { CTL_HW, HW_MEMSIZE }; + + int64_t physical_memory = 0; + size_t length = sizeof(int64_t); + + if (sysctl(mib, 2, &physical_memory, &length, NULL, 0) == -1) + { + physical_memory = 0; + } + + return physical_memory; +} + +int update_meminfo(void) +{ + /* XXX implement remaining memory-related variables (see conky.h) */ + /* XXX conky breaks the values ... :( probably some rounding problem... + Though we get the right values (based on top) */ + /* XXX probably investigate the "probably apple keeps some info secret" */ + + vm_size_t page_size = getpagesize(); // get pagesize in bytes + unsigned long swap_avail, swap_free; + + static + libtop_tsamp_t * tsamp = nullptr; + if (!tsamp) + { + tsamp = new libtop_tsamp_t; + if (!tsamp) + return 0; + + memset(tsamp, 0, sizeof(libtop_tsamp_t)); + tsamp->pagesize = page_size; + } + + /* get physical memory */ + uint64_t physical_memory = get_physical_memory() / 1024; + info.memmax = physical_memory; + + /* + * get general memory stats + * but first update pages stolen count + */ + update_pages_stolen(tsamp); + if (libtop_tsamp_update_vm_stats(tsamp) == KERN_FAILURE) + return 0; + + /* + * This is actually a tricky part. + * + * MenuMeters, Activity Monitor and top show different values. + * Our code uses top's implementation because: + * - it is apple's tool + * - professional projects such as osquery follow it + * - Activity Monitor seems to be hiding the whole truth (e.g. for being user friendly) + * + * STEPS: + * - get stolen pages count + * Occassionaly host_statistics64 doesn't return correct values (see https://stackoverflow.com/questions/14789672/why-does-host-statistics64-return-inconsistent-results) + * We need to get the count of stolen pages and add it to wired pages count. + * This is a known bug and apple has implemented the function update_pages_stolen(). + * + * - use vm_stat.free_count instead of the sum of wired, active and inactive + * Based on https://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process + * summing up wired, active and inactive is what we should do BUT, based on top, this is incorrect. + * Seems like apple keeps some info "secret"! + */ + info.mem = physical_memory - (tsamp->vm_stat.free_count * page_size / 1024); + + /* rest memory related variables */ + info.memwithbuffers = info.mem; + info.memeasyfree = info.memfree = info.memmax - info.mem; + + if ((swapmode(&swap_avail, &swap_free)) >= 0) + { + info.swapmax = swap_avail; + info.swap = (swap_avail - swap_free); + info.swapfree = swap_free; + } + else + { + info.swapmax = 0; + info.swap = 0; + info.swapfree = 0; + } + + return 0; +} + +int update_net_stats(void) +{ + struct net_stat *ns; + double delta; + long long r, t, last_recv, last_trans; + struct ifaddrs *ifap, *ifa; + struct if_data *ifd; + + /* get delta */ + delta = current_update_time - last_update_time; + if (delta <= 0.0001) { + return 0; + } + + if (getifaddrs(&ifap) < 0) + { + return 0; + } + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) + { + ns = get_net_stat((const char *) ifa->ifa_name, NULL, NULL); + + if (ifa->ifa_flags & IFF_UP) + { + struct ifaddrs *iftmp; + + ns->up = 1; + last_recv = ns->recv; + last_trans = ns->trans; + + if (ifa->ifa_addr->sa_family != AF_LINK) + { + continue; + } + + for (iftmp = ifa->ifa_next; + iftmp != NULL && strcmp(ifa->ifa_name, iftmp->ifa_name) == 0; + iftmp = iftmp->ifa_next) + { + if (iftmp->ifa_addr->sa_family == AF_INET) + { + memcpy(&(ns->addr), iftmp->ifa_addr, iftmp->ifa_addr->sa_len); + } + } + + ifd = (struct if_data *) ifa->ifa_data; + r = ifd->ifi_ibytes; + t = ifd->ifi_obytes; + + if (r < ns->last_read_recv) + { + ns->recv += ((long long) 4294967295U - + ns->last_read_recv) + r; + } + else + { + ns->recv += (r - ns->last_read_recv); + } + + ns->last_read_recv = r; + + if (t < ns->last_read_trans) + { + ns->trans += ((long long) 4294967295U - + ns->last_read_trans) + t; + } + else + { + ns->trans += (t - ns->last_read_trans); + } + + ns->last_read_trans = t; + + /* calculate speeds */ + ns->recv_speed = (ns->recv - last_recv) / delta; + ns->trans_speed = (ns->trans - last_trans) / delta; + } + else + { + ns->up = 0; + } + } + + freeifaddrs(ifap); + return 0; +} + +int update_threads(void) +{ + helper_update_threads_processes(); + return 0; +} + +/* + * XXX This seems to be wrong... We must first find the threads (using thread_info() ) + * + * Get list of all processes. + * Foreach process check its state. + * If it is RUNNING it means that it actually has some threads + * that are in TH_STATE_RUNNING. + * Foreach pid and foreach pid's threads check their state and increment + * the run_threads counter acordingly. + */ +int update_running_threads(void) +{ + struct kinfo_proc *p = NULL; + int proc_count = 0; + int run_threads = 0; + + proc_count = helper_get_proc_list(&p); + + if (proc_count == -1) + return 0; + + for (int i = 0; i < proc_count; i++) + if (p[i].kp_proc.p_stat & SRUN) + { + pid_t pid = 0; + struct proc_taskinfo pti; + struct proc_threadinfo pthi; + int num_threads = 0; + + pid = p[i].kp_proc.p_pid; + + /* get total number of threads this pid has */ + if (sizeof(pti) == proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti))) + { + num_threads = pti.pti_threadnum; + } + else continue; + + /* foreach thread check its state */ + for (int i = 0; i < num_threads; i++) + if (sizeof(pthi) == proc_pidinfo(pid, PROC_PIDTHREADINFO, i, &pthi, sizeof(pthi))) + { + if (pthi.pth_run_state == TH_STATE_RUNNING) + run_threads++; + } + else continue; + } + + free(p); + info.run_threads = run_threads; + return 0; +} + +int update_total_processes(void) +{ + helper_update_threads_processes(); + return 0; + + /* + * WARNING: You may stumble upon this implementation: + * https://stackoverflow.com/questions/8141913/is-there-a-lightweight-way-to-obtain-the-current-number-of-processes-in-linux + * + * This method DOESN'T find the correct number of tasks. + * + * This is probably (??) because on macOS there is no option for KERN_PROC_KTHREAD like there is in FreeBSD + * + * In FreeBSD's sysctl.h we can see the following: + * + * KERN_PROC_KTHREAD all processes (user-level plus kernel threads) + * KERN_PROC_ALL all user-level processes + * KERN_PROC_PID processes with process ID arg + * KERN_PROC_PGRP processes with process group arg + * KERN_PROC_SESSION processes with session arg + * KERN_PROC_TTY processes with tty(4) arg + * KERN_PROC_UID processes with effective user ID arg + * KERN_PROC_RUID processes with real user ID arg + * + * Though in macOS's sysctl.h there are only: + * + * KERN_PROC_ALL everything + * KERN_PROC_PID by process id + * KERN_PROC_PGRP by process group id + * KERN_PROC_SESSION by session of pid + * KERN_PROC_TTY by controlling tty + * KERN_PROC_UID by effective uid + * KERN_PROC_RUID by real uid + * KERN_PROC_LCID by login context id + * + * Probably by saying "everything" they mean that KERN_PROC_ALL gives all processes (user-level plus kernel threads) + * ( So basically this is the problem with the old implementation ) + */ +} + +int update_running_processes(void) +{ + struct kinfo_proc *p = NULL; + int proc_count = 0; + int run_procs = 0; + + proc_count = helper_get_proc_list(&p); + + if (proc_count == -1) + return 0; + + for (int i = 0; i < proc_count; i++) + { + int state = p[i].kp_proc.p_stat; + + if (state == SRUN) // XXX this check needs to be fixed... + run_procs++; + } + + free(p); + info.run_procs = run_procs; + return 0; +} + +/* + * get_cpu_count + * + * The macOS implementation gets the number of active cpus + * in compliance with linux implementation. + */ +void get_cpu_count(void) +{ + int cpu_count = 0; + + if (GETSYSCTL("hw.activecpu", cpu_count) == 0) { + info.cpu_count = cpu_count; + } else { + fprintf(stderr, "Cannot get hw.activecpu\n"); + info.cpu_count = 0; + } + + /* XXX this can be moved to update_cpu_usage() but keep here to follow linux implementation */ + if (!info.cpu_usage) + { + /* + * Allocate ncpus+1 slots because cpu_usage[0] is overall usage. + */ + info.cpu_usage = (float *) malloc((info.cpu_count + 1) * sizeof(float)); + if (info.cpu_usage == NULL) + { + CRIT_ERR(NULL, NULL, "malloc"); + } + } +} + +/* + * used by update_cpu_usage() + */ +struct cpu_info +{ + long oldtotal; + long oldused; +}; + +int update_cpu_usage(void) +{ + /* XXX add support for multiple cpus (see linux.cc) */ + + static bool + cpu_setup = 0; + + long used, total; + static struct cpu_info *cpu = NULL; + unsigned int malloc_cpu_size = 0; + extern void* global_cpu; + + struct cpusample sample; + + static pthread_mutex_t last_stat_update_mutex = PTHREAD_MUTEX_INITIALIZER; + static double last_stat_update = 0.0; + + /* since we use wrappers for this function, the update machinery + * can't eliminate double invocations of this function. Check for + * them here, otherwise cpu_usage counters are freaking out. */ + pthread_mutex_lock(&last_stat_update_mutex); + if (last_stat_update == current_update_time) { + pthread_mutex_unlock(&last_stat_update_mutex); + return 0; + } + last_stat_update = current_update_time; + pthread_mutex_unlock(&last_stat_update_mutex); + + /* add check for !info.cpu_usage since that mem is freed on a SIGUSR1 */ + if ((cpu_setup == 0) || (!info.cpu_usage)) + { + get_cpu_count(); + cpu_setup = 1; + } + + if (!global_cpu) + { + /* + * Allocate ncpus+1 slots because cpu_usage[0] is overall usage. + */ + malloc_cpu_size = (info.cpu_count + 1) * sizeof(struct cpu_info); + cpu = (cpu_info *) malloc(malloc_cpu_size); + memset(cpu, 0, malloc_cpu_size); + global_cpu = cpu; + } + + get_cpu_sample(&sample); + total = sample.totalUserTime + sample.totalIdleTime + sample.totalSystemTime; + used = total - sample.totalIdleTime; + + if ((total - cpu[0].oldtotal) != 0) + { + info.cpu_usage[0] = ((double) (used - cpu[0].oldused)) / (double) (total - cpu[0].oldtotal); + } + else + { + info.cpu_usage[0] = 0; + } + + cpu[0].oldused = used; + cpu[0].oldtotal = total; + + return 0; +} + +int update_load_average(void) +{ + double v[3]; + + getloadavg(v, 3); + + info.loadavg[0] = (double) v[0]; + info.loadavg[1] = (double) v[1]; + info.loadavg[2] = (double) v[2]; + + return 0; +} + +double get_acpi_temperature(int fd) +{ + printf("get_acpi_temperature: STUB\n"); + return 0.0; +} + +void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item) +{ + printf("get_battery_stuff: STUB\n"); +} + +int get_battery_perct(const char *bat) +{ + printf("get_battery_perct: STUB\n"); + return 1; +} + +double get_battery_perct_bar(struct text_object *obj) +{ + printf("get_battery_perct_bar: STUB\n"); + return 0.0; +} + +int open_acpi_temperature(const char *name) +{ + printf("open_acpi_temperature: STUB\n"); + + (void)name; + /* Not applicable for FreeBSD. */ + return 0; +} + +void get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size, const char *adapter) +{ + printf("get_acpi_ac_adapter: STUB\n"); +} + +void get_acpi_fan(char *p_client_buffer, size_t client_buffer_size) +{ + printf("get_acpi_fan: STUB\n"); +} + +/* void */ +char get_freq(char *p_client_buffer, size_t client_buffer_size, const char *p_format, + int divisor, unsigned int cpu) +{ + /* + * For now, we get the factory cpu frequency, not **current** cpu frequency + * (Also, it is always the same for every core, so ignore |cpu| argument) + */ + + // XXX Probably find a way to get **current** cpu frequency + + int mib[2]; + unsigned int freq; + size_t len; + + if (!p_client_buffer || client_buffer_size <= 0 || !p_format + || divisor <= 0) { + return 0; + } + + mib[0] = CTL_HW; + mib[1] = HW_CPU_FREQ; + len = sizeof(freq); + + if (sysctl(mib, 2, &freq, &len, NULL, 0) == 0) + { + /* + * convert to MHz + */ + divisor *= 1000000; + + snprintf(p_client_buffer, client_buffer_size, p_format, + (float) freq / divisor); + } + else + { + snprintf(p_client_buffer, client_buffer_size, p_format, 0.0f); + return 0; + } + + return 1; +} + +#if 0 +void update_wifi_stats(void) +{ + printf("update_wifi_stats: STUB but also in #if 0\n"); +} +#endif + +int update_diskio(void) +{ + printf("update_diskio: STUB\n"); + return 0; +} + +void get_battery_short_status(char *buffer, unsigned int n, const char *bat) +{ + printf("get_battery_short_status: STUB\n"); +} + +int get_entropy_avail(unsigned int * val) +{ + (void)val; + return 1; +} +int get_entropy_poolsize(unsigned int * val) +{ + (void)val; + return 1; +} + +/****************************************** + * get top info section * + ******************************************/ + +/* + * Calculate a process' cpu usage percentage + */ +static void calc_cpu_usage_for_proc(struct process *proc, uint64_t total) +{ + float mul = 100.0; + if(top_cpu_separate.get(*state)) + mul *= info.cpu_count; + + proc->amount = mul * (proc->user_time + proc->kernel_time) / (float) total; +} + +/* + * calculate total CPU usage based on total CPU usage + * of previous iteration stored inside |process| struct + */ +static void calc_cpu_total(struct process *proc, uint64_t *total) +{ + uint64_t current_total = 0; /* of current iteration */ + //uint64_t total = 0; /* delta */ + struct cpusample sample; + + get_cpu_sample(&sample); + current_total = sample.totalUserTime + sample.totalIdleTime + sample.totalSystemTime; + + *total = current_total - proc->previous_total_cpu_time; + proc->previous_total_cpu_time = current_total; + + *total = ((*total / sysconf(_SC_CLK_TCK)) * 100) / info.cpu_count; +} + +/* + * calc_cpu_time_for_proc + * + * calculates user_time and kernel_time and sets the contents of the |process| struct + * excessively based on process_parse_stat() from linux.cc + */ +static void calc_cpu_time_for_proc(struct process *process, const struct proc_taskinfo *pti) +{ + unsigned long long user_time = 0; + unsigned long long kernel_time = 0; + + process->user_time = pti->pti_total_user; + process->kernel_time = pti->pti_total_system; + + /* user_time and kernel_time are in nanoseconds, total_cpu_time in centiseconds. + * Therefore we divide by 10^7 . */ + process->user_time /= 10000000; + process->kernel_time /= 10000000; + + process->total_cpu_time = process->user_time + process->kernel_time; + if (process->previous_user_time == ULONG_MAX) { + process->previous_user_time = process->user_time; + } + if (process->previous_kernel_time == ULONG_MAX) { + process->previous_kernel_time = process->kernel_time; + } + + /* store the difference of the user_time */ + user_time = process->user_time - process->previous_user_time; + kernel_time = process->kernel_time - process->previous_kernel_time; + + /* backup the process->user_time for next time around */ + process->previous_user_time = process->user_time; + process->previous_kernel_time = process->kernel_time; + + /* store only the difference of the user_time here... */ + process->user_time = user_time; + process->kernel_time = kernel_time; +} + +/* + * finds top-information only for one process which is represented by a kinfo_proc struct + * this function is called mutliple types ( one foreach process ) to implement get_top_info() + */ +static void get_top_info_for_kinfo_proc(struct kinfo_proc *p) +{ + struct process *proc = NULL; + struct proc_taskinfo pti; + pid_t pid; + + pid = p->kp_proc.p_pid; + proc = get_process(pid); + + free_and_zero(proc->name); + free_and_zero(proc->basename); + + proc->name = strndup(p->kp_proc.p_comm, text_buffer_size.get(*state)); + proc->basename = strndup(p->kp_proc.p_comm, text_buffer_size.get(*state)); + proc->uid = p->kp_eproc.e_pcred.p_ruid; + proc->time_stamp = g_time; + + if(sizeof(pti) == proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti))) + { + /* vsize, rss are in bytes thus we dont have to convert */ + proc->vsize = pti.pti_virtual_size; + proc->rss = pti.pti_resident_size; + + __block uint64_t t = 0; + + __block bool calc_cpu_total_finished = false; + __block bool calc_proc_total_finished = false; + + dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + /* calc CPU time for process */ + calc_cpu_time_for_proc(proc, &pti); + + calc_proc_total_finished = true; + }); + + dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + /* calc total CPU time (considering current process) */ + calc_cpu_total(proc, &t); + + calc_cpu_total_finished = true; + }); + + /* + * wait until done + */ + while (!(calc_cpu_total_finished && calc_proc_total_finished)) + ; + + /* calc the amount(%) of CPU the process used */ + calc_cpu_usage_for_proc(proc, t); + } +} + +/* While topless is obviously better, top is also not bad. */ + +void get_top_info(void) +{ + int proc_count = 0; + struct kinfo_proc *p = NULL; + + /* + * QUICKFIX for #16 + * XXX if we run conky -t '${top_mem mem 1}' it will crash because info.cpu_count is not initialised. + * + * We can initialise it down here, but it seems like in the linux implementation of get_top_info() there is no + * call to the get_cpu_count() function. Neither is there in core.cc... If this is the case, when is info.cpu_count + * initialised??? + * + * Find a proper better place for get_cpu_count() call. (for comformance with linux.cc) + */ + get_cpu_count(); + + /* + * get processes count + * and create the processes list + */ + proc_count = helper_get_proc_list(&p); + + if (proc_count == -1) + return; + + /* + * get top info for-each process + */ + for (int i = 0; i < proc_count; i++) + { + if (!((p[i].kp_proc.p_flag & P_SYSTEM)) && *p[i].kp_proc.p_comm != '\0') + { + get_top_info_for_kinfo_proc(&p[i]); + } + } + + free(p); +} + +/********************************************************************************************* + * System Integrity Protection * + *********************************************************************************************/ + +#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_9) + +/* + * Check if a flag is enabled based on the csr_config variable + * Also, flip the result on occasion + */ +bool _csr_check(int aMask, bool aFlipflag) +{ + bool bit = (info.csr_config & aMask); + + if (aFlipflag) + return !bit; + + return bit; +} + +/* + * Extract info from the csr_config variable and set the flags struct + */ +void fill_csr_config_flags_struct(void) +{ + info.csr_config_flags.csr_allow_apple_internal = _csr_check(CSR_ALLOW_APPLE_INTERNAL, 0); + info.csr_config_flags.csr_allow_untrusted_kexts = _csr_check(CSR_ALLOW_UNTRUSTED_KEXTS, 1); + info.csr_config_flags.csr_allow_task_for_pid = _csr_check(CSR_ALLOW_TASK_FOR_PID, 1); + info.csr_config_flags.csr_allow_unrestricted_fs = _csr_check(CSR_ALLOW_UNRESTRICTED_FS, 1); + info.csr_config_flags.csr_allow_kernel_debugger = _csr_check(CSR_ALLOW_KERNEL_DEBUGGER, 1); + info.csr_config_flags.csr_allow_unrestricted_dtrace = _csr_check(CSR_ALLOW_UNRESTRICTED_DTRACE, 1); + info.csr_config_flags.csr_allow_unrestricted_nvram = _csr_check(CSR_ALLOW_UNRESTRICTED_NVRAM, 1); + info.csr_config_flags.csr_allow_device_configuration = _csr_check(CSR_ALLOW_DEVICE_CONFIGURATION, 0); + info.csr_config_flags.csr_allow_any_recovery_os = _csr_check(CSR_ALLOW_ANY_RECOVERY_OS, 1); + info.csr_config_flags.csr_allow_user_approved_kexts = _csr_check(CSR_ALLOW_UNAPPROVED_KEXTS, 1); +} + +/* + * Get SIP configuration ( sets csr_config and csr_config_flags ) + */ +int get_sip_status(void) +{ + if (csr_get_active_config == nullptr) /* check if weakly linked symbol exists */ + { + NORM_ERR("$sip_status will not work on this version of macOS\n"); + return 0; + } + + csr_get_active_config(&info.csr_config); + fill_csr_config_flags_struct(); + + return 0; +} + +/* + * Prints SIP status or a specific SIP feature status depending on the argument passed + * to $sip_status command + * + * Variables that can be passed to $sip_status command + * + * nothing --> print enabled / disabled + * 0 --> allow_apple_internal + * 1 --> allow_untrusted_kexts + * 2 --> allow_task_for_pid + * 3 --> allow_unrestricted_fs + * 4 --> allow_kernel_debugger + * 5 --> allow_unrestricted_dtrace + * 6 --> allow_unrestricted_nvram + * 7 --> allow_device_configuration + * 8 --> allow_any_recovery_os + * 9 --> allow_user_approved_kexts + * a --> check if unsupported configuration ---> this is not an apple SIP flag. This is for us. + * + * The print function is designed to show 'YES' if a specific protection measure is ENABLED. + * For example, if SIP is configured to disallow untrusted kexts, then our function will print 'YES'. + * Thus, it doesnt print 'YES' in the case SIP allows untrusted kexts. + * + * For this reason, your conkyrc should say for example: Untrusted Kexts Protection: ${sip_status 1} + * You should not write: "Allow Untrusted Kexts", this is wrong. + */ +void print_sip_status(struct text_object *obj, char *p, int p_max_size) +{ + if (csr_get_active_config == nullptr) /* check if weakly linked symbol exists */ + { + snprintf(p, p_max_size, "%s", "unsupported"); + NORM_ERR("$sip_status will not work on this version of macOS\n"); + return; + } + + /* conky window output */ + (void)obj; + + if (!obj->data.s) + return; + + if (strlen(obj->data.s) == 0) + { + snprintf(p, p_max_size, "%s", (info.csr_config == CSR_VALID_FLAGS) ? "disabled" : "enabled"); + } + else if(strlen(obj->data.s) == 1) + { + switch (obj->data.s[0]) + { + case '0': + snprintf(p, p_max_size, "%s", info.csr_config_flags.csr_allow_apple_internal ? "YES" : "NO"); + break; + case '1': + snprintf(p, p_max_size, "%s", info.csr_config_flags.csr_allow_untrusted_kexts ? "YES" : "NO"); + break; + case '2': + snprintf(p, p_max_size, "%s", info.csr_config_flags.csr_allow_task_for_pid ? "YES" : "NO"); + break; + case '3': + snprintf(p, p_max_size, "%s", info.csr_config_flags.csr_allow_unrestricted_fs ? "YES" : "NO"); + break; + case '4': + snprintf(p, p_max_size, "%s", info.csr_config_flags.csr_allow_kernel_debugger ? "YES" : "NO"); + break; + case '5': + snprintf(p, p_max_size, "%s", info.csr_config_flags.csr_allow_unrestricted_dtrace ? "YES" : "NO"); + break; + case '6': + snprintf(p, p_max_size, "%s", info.csr_config_flags.csr_allow_unrestricted_nvram ? "YES" : "NO"); + break; + case '7': + snprintf(p, p_max_size, "%s", info.csr_config_flags.csr_allow_device_configuration ? "YES" : "NO"); + break; + case '8': + snprintf(p, p_max_size, "%s", info.csr_config_flags.csr_allow_any_recovery_os ? "YES" : "NO"); + break; + case '9': + snprintf(p, p_max_size, "%s", info.csr_config_flags.csr_allow_user_approved_kexts ? "YES" : "NO"); + break; + case 'a': + snprintf(p, p_max_size, "%s", (info.csr_config && (info.csr_config != CSR_ALLOW_APPLE_INTERNAL)) ? "unsupported configuration, beware!" : "configuration is ok"); + break; + default: + snprintf(p, p_max_size, "%s", "unsupported"); + NORM_ERR("print_sip_status: unsupported argument passed to $sip_status"); + break; + } + } else { /* bad argument */ + snprintf(p, p_max_size, "%s", "unsupported"); + NORM_ERR("print_sip_status: unsupported argument passed to $sip_status"); + } +} + +#else /* Mavericks and before */ +/* + * Versions prior to Yosemite DONT EVEN DEFINE csr_get_active_config() function. Thus we must avoid calling this function! + */ + +int get_sip_status(void) +{ + /* Does not do anything intentionally */ + return 0; +} + +void print_sip_status(struct text_object *obj, char *p, int p_max_size) +{ + /* conky window output */ + (void)obj; + + if (!obj->data.s) + return; + + if (strlen(obj->data.s) == 0) + { + snprintf(p, p_max_size, "%s", "error unsupported"); + } + else if(strlen(obj->data.s) == 1) + { + switch (obj->data.s[0]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'a': + snprintf(p, p_max_size, "%s", "error unsupported"); + break; + default: + snprintf(p, p_max_size, "%s", "unsupported"); + NORM_ERR("print_sip_status: unsupported argument passed to $sip_status"); + break; + } + } + else + { /* bad argument */ + snprintf(p, p_max_size, "%s", "unsupported"); + NORM_ERR("print_sip_status: unsupported argument passed to $sip_status"); + } +} + +#endif diff --git a/src/darwin.h b/src/darwin.h new file mode 100644 index 00000000..db086ae6 --- /dev/null +++ b/src/darwin.h @@ -0,0 +1,59 @@ +/* + * Conky, a system monitor, based on torsmo + * + * Any original torsmo code is licensed under the BSD license + * + * All code written since the fork of torsmo is licensed under the GPL + * + * Please see COPYING for details + * + * Copyright (c) 2018, npyl + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef DARWIN_H +#define DARWIN_H + +#include +#include +#include +#include + +/* + * on versions prior to Sierra clock_gettime is not implemented. + */ +#ifndef HAVE_CLOCK_GETTIME + +/* only CLOCK_REALTIME and CLOCK_MONOTONIC are emulated */ +#ifndef CLOCK_REALTIME +# define CLOCK_REALTIME 0 +#endif +#ifndef CLOCK_MONOTONIC +# define CLOCK_MONOTONIC 1 +#endif + +int clock_gettime(int clock_id, struct timespec *ts); +#endif /* ifndef HAVE_CLOCK_GETTIME */ + +int update_running_threads(void); + +int get_entropy_avail(unsigned int *); +int get_entropy_poolsize(unsigned int *); + +/* System Integrity Protection */ +int get_sip_status(void); +void print_sip_status(struct text_object *obj, char *p, int p_max_size); + +#endif /*DARWIN_H*/ diff --git a/src/darwin_sip.h b/src/darwin_sip.h new file mode 100644 index 00000000..dc295473 --- /dev/null +++ b/src/darwin_sip.h @@ -0,0 +1,64 @@ +/* + * Conky, a system monitor, based on torsmo + * + * Any original torsmo code is licensed under the BSD license + * + * All code written since the fork of torsmo is licensed under the GPL + * + * Please see COPYING for details + * + * Copyright (c) 2018, npyl + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// +// Defines for System Integrity Protection monitoring +// based on csrstat tool by Pike R. Alpha. https://github.com/Piker-Alpha/csrstat +// + +#ifndef DARWIN_SIP_H +#define DARWIN_SIP_H + +/* Rootless configuration flags */ +#define CSR_ALLOW_UNTRUSTED_KEXTS (1 << 0) // 1 +#define CSR_ALLOW_UNRESTRICTED_FS (1 << 1) // 2 +#define CSR_ALLOW_TASK_FOR_PID (1 << 2) // 4 +#define CSR_ALLOW_KERNEL_DEBUGGER (1 << 3) // 8 +#define CSR_ALLOW_APPLE_INTERNAL (1 << 4) // 16 +#define CSR_ALLOW_UNRESTRICTED_DTRACE (1 << 5) // 32 +#define CSR_ALLOW_UNRESTRICTED_NVRAM (1 << 6) // 64 +#define CSR_ALLOW_DEVICE_CONFIGURATION (1 << 7) // 128 +#define CSR_ALLOW_ANY_RECOVERY_OS (1 << 8) // 256 +#define CSR_ALLOW_UNAPPROVED_KEXTS (1 << 9) // 512 + +#define CSR_VALID_FLAGS (CSR_ALLOW_UNTRUSTED_KEXTS | \ + CSR_ALLOW_UNRESTRICTED_FS | \ + CSR_ALLOW_TASK_FOR_PID | \ + CSR_ALLOW_KERNEL_DEBUGGER | \ + CSR_ALLOW_APPLE_INTERNAL | \ + CSR_ALLOW_UNRESTRICTED_DTRACE | \ + CSR_ALLOW_UNRESTRICTED_NVRAM | \ + CSR_ALLOW_DEVICE_CONFIGURATION | \ + CSR_ALLOW_ANY_RECOVERY_OS | \ + CSR_ALLOW_UNAPPROVED_KEXTS) + +/* Syscalls */ +// mark these symbols as weakly linked, as they may not be available +// at runtime on older OS X versions. +extern "C" { + int csr_get_active_config(information::csr_config_t* config) __attribute__((weak_import)); +}; + +#endif diff --git a/src/entropy.cc b/src/entropy.cc index c1726169..e43c1956 100644 --- a/src/entropy.cc +++ b/src/entropy.cc @@ -45,6 +45,8 @@ #include "solaris.h" #elif defined(__HAIKU__) #include "haiku.h" +#elif defined(__APPLE__) && defined(__MACH__) +#include "darwin.h" #endif struct _entropy { diff --git a/src/fs.cc b/src/fs.cc index 1e317764..a7eae4d8 100644 --- a/src/fs.cc +++ b/src/fs.cc @@ -54,12 +54,15 @@ #include "dragonfly.h" #elif defined(__HAIKU__) #include "haiku.h" +#elif defined(__APPLE__) && defined(__MACH__) +#include "darwin.h" #endif #if !defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) && \ !defined (__OpenBSD__) && !defined(__FreeBSD__) && \ - !defined(__DragonFly__) && !defined(__sun) && !defined(__HAIKU__) + !defined(__DragonFly__) && !defined(__sun) && !defined(__HAIKU__) && \ + !(defined(__APPLE__) && defined(__MACH__)) #include #endif @@ -156,7 +159,7 @@ void get_fs_type(const char *path, char *result) { #if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) || \ - defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__) || defined(__HAIKU__) + defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__) || defined(__HAIKU__) || (defined(__APPLE__) && defined(__MACH__)) struct statfs64 s; if (statfs64(path, &s) == 0) { diff --git a/src/luamm.cc b/src/luamm.cc index 71eaab26..0afae49f 100644 --- a/src/luamm.cc +++ b/src/luamm.cc @@ -57,7 +57,13 @@ namespace lua { lua_pushstring(l, e.what()); } catch(...) { - lua_pushstring(l, ptr->__cxa_exception_type()->name()); +#if defined(__APPLE__) && defined(__MACH__) + //lua_pushstring(l, ptr->__cxa_exception_type()->name()); + printf("%s: FIXME: no member named '__cxa_exception_type' in 'std::exception_ptr' \n", __func__); + lua_pushstring(l, "FIXME: in luamm.cc"); +#else + lua_pushstring(l, ptr->__cxa_exception_type()->name()); +#endif } return 1; } diff --git a/src/semaphore.hh b/src/semaphore.hh index d3ce9f94..6694cd05 100644 --- a/src/semaphore.hh +++ b/src/semaphore.hh @@ -29,47 +29,109 @@ #include #include +#if defined(__APPLE__) && defined(__MACH__) + +/* + * On Darwin, unnamed semaphores are not supported! + * The only close equivalent to unnamed semaphores is using + * GCD! + */ + +#include + +class semaphore { + dispatch_semaphore_t sem; + + semaphore(const semaphore &) = delete; + semaphore& operator=(const semaphore &) = delete; +public: + semaphore(unsigned int value = 0) throw(std::logic_error) + { + sem = dispatch_semaphore_create(value); + + if (!sem) + throw std::logic_error(strerror(errno)); + } + + ~semaphore() throw() + { + dispatch_release(sem); + } + void post() throw(std::overflow_error) + { + dispatch_semaphore_signal(sem); + } + + void wait() throw() + { + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + } + + bool trywait() throw() + { + /* XXX Quick patch */ +#define DISPATCH_EAGAIN 49 + + int ret = dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW); + + while (ret > 0) + { + if(ret == DISPATCH_EAGAIN) + return false; + else if(errno != EINTR) + abort(); + } + return true; + } +}; + +#else + #include class semaphore { - sem_t sem; - - semaphore(const semaphore &) = delete; - semaphore& operator=(const semaphore &) = delete; + sem_t sem; + + semaphore(const semaphore &) = delete; + semaphore& operator=(const semaphore &) = delete; public: - semaphore(unsigned int value = 0) throw(std::logic_error) - { - if(sem_init(&sem, 0, value)) - throw std::logic_error(strerror(errno)); - } - - ~semaphore() throw() - { sem_destroy(&sem); } - - void post() throw(std::overflow_error) - { - if(sem_post(&sem)) - throw std::overflow_error(strerror(errno)); - } - - void wait() throw() - { - while(sem_wait(&sem)) { - if(errno != EINTR) - abort(); - } - } - - bool trywait() throw() - { - while(sem_trywait(&sem)) { - if(errno == EAGAIN) - return false; - else if(errno != EINTR) - abort(); - } - return true; - } + semaphore(unsigned int value = 0) throw(std::logic_error) + { + if(sem_init(&sem, 0, value)) + throw std::logic_error(strerror(errno)); + } + + ~semaphore() throw() + { sem_destroy(&sem); } + + void post() throw(std::overflow_error) + { + if(sem_post(&sem)) + throw std::overflow_error(strerror(errno)); + } + + void wait() throw() + { + while(sem_wait(&sem)) { + if(errno != EINTR) + abort(); + } + } + + bool trywait() throw() + { + while(sem_trywait(&sem)) { + + if(errno == EAGAIN) + return false; + else if(errno != EINTR) + abort(); + } + return true; + } }; +#endif /* defined(__APPLE__) && defined(__MACH__) */ + #endif + diff --git a/src/top.h b/src/top.h index 328e28d1..ccbe1ec5 100644 --- a/src/top.h +++ b/src/top.h @@ -97,6 +97,7 @@ struct process { unsigned long previous_user_time; unsigned long previous_kernel_time; unsigned long total_cpu_time; + unsigned long previous_total_cpu_time; unsigned long long vsize; unsigned long long rss; #ifdef BUILD_IOSTATS