Tracing FreeBSD TCP Retransmits - tcp

Brendan Gregg has developed a great tool, "tcpretrans" based on the Dynamic Tracing feature of the Linux kernel. He explained it here: https://www.brendangregg.com/blog/2014-09-06/linux-ftrace-tcp-retransmit-tracing.html
The tool utilizes a low overhead approach to demonstrate TCP-retransmits happened. I wonder to know if there is a similar tool or DTrace script that could be utilized for such a purpose.
I am stuck in a situation where need to know what the retransmits are so I can dig more.

Try this from FreeBSD DTrace Network Stack:
#!/usr/sbin/dtrace -s
#pragma D option quiet
#pragma D option switchrate=10Hz
dtrace:::BEGIN
{
printf(" %30s %-6s %30s %-6s %-6s %s\n\n", "SADDR", "SPORT",
"DADDR", "DPORT", "BYTES", "FLAGS");
}
tcp:::receive,
tcp:::send
{
printf(" %30s %-6u %30s %-6u %-6u (%s%s%s%s%s%s\b)\n",
args[2]->ip_saddr, args[4]->tcp_sport,
args[2]->ip_daddr, args[4]->tcp_dport,
args[2]->ip_plength - args[4]->tcp_offset,
(args[4]->tcp_flags & TH_FIN) ? "FIN|" : "",
(args[4]->tcp_flags & TH_SYN) ? "SYN|" : "",
(args[4]->tcp_flags & TH_RST) ? "RST|" : "",
(args[4]->tcp_flags & TH_PUSH) ? "PSH|" : "",
(args[4]->tcp_flags & TH_ACK) ? "ACK|" : "",
(args[4]->tcp_flags & TH_URG) ? "URG|" : "");
}

Related

Notification sounds on RStudio server [duplicate]

When I run R scripts I go do something else on a different desktop. If I don't check frequently, I never know when something is finished. Is there a way to invoke a beep (like a system beep) or get R to play a sound or notify growl via some code at the end of my script?
I have a package (beepr) with the sole purpose of making notification sounds in R which should work cross-platform. Run the following to install beepr and make a sound:
install.packages("beepr")
library(beepr)
beep()
More info at github: https://github.com/rasmusab/beepr
alarm()
The alarm function. It works by sending \a to the console
On MacOSX you can let the computer speak:
system("say Just finished!")
and you can also change the artificial voice that will speak:
system("say -v Kathy Just finished!")
You can pick any voice that is available on your computer. On Yosemite you can see which voices are installed in System Preferences -> Dictation & Speech -> Text to Speech.
You should have it tweet when it's done: http://cran.r-project.org/web/packages/twitteR/index.html
alarm doesn't work on my Windows machine so I created a function that does actually make noise.
beep <- function(n = 3){
for(i in seq(n)){
system("rundll32 user32.dll,MessageBeep -1")
Sys.sleep(.5)
}
}
This clearly could only work on Windows but I don't guarantee it will even run on an arbitrary Windows computer. I've only tested it on my machine but I figured I'd post it in case anybody has the same problem with alarm that I do.
cat('Hello world!\a')
How about something reasonably OS independent for OSes with GUIs and web-browsers? It even works on RStudio Server!
browseURL('https://www.youtube.com/watch?v=QH2-TGUlwu4')
Not only that, you can also also put some epic music from Youtube when the program is done looping :) (For Ubuntu/Debian:)
system("xdg-open 'http://www.youtube.com/watch?v=9jK-NcRmVcw'")
UPDATE:
With macOS 10.9 (Mavericks) and later, you can post notifications using plain AppleScript:
theTitle <- "A Title"
theMsg <- "A message here"
cmd <- paste("osascript -e ", "'display notification ", '"', theMsg, '"', ' with title ', '"', theTitle, '"', "'", sep='')
system(cmd)
This removes the need to install terminal-notifier, referenced below.
--
I've got terminal-notifier installed on my Mac to get desktop notifications from the command line. You can then wrap up a call to the system() command like this (change the path, obviously):
notify <- function(msgString='Message from R', titleString='Message from R', speakIt=FALSE) {
cmd <- paste('~/terminal-notifier/terminal-notifier.app/Contents/MacOS/terminal-notifier -message ', '"', msgString, '" -title "', titleString, '"', sep='')
system(cmd)
if (speakIt) {
system(paste('say', msgString))
}
}
You can call the function like this
notify("R is done", "Message from R", speakIt=TRUE)
to get a message like this:
Update: Included #VLC's say command.
Please use shell.exec("url") to open some YouTube clip on Windows
Or if you're using GNU/Linux distro and have pcspkr module blacklisted (PC speaker was always annoying me), try combining system with some auditive/visual notification, e.g.
system("aplay -t wav /usr/share/sounds/phone.wav") # for auditive bell (an I mean it literary)
system("zenity --title=\"R script info\" --text=\"Script has finished with zero exit status\" --info") # for GTK dialog
You can check zenity manual if you prefer alert in, say, notification area... But, with system function, you can do pretty much anything: send an email, run some other script, reboot the machine, sudo rm -rf *.*, etc. anything... and I mean it.
But this stands only IF you're running GNU/Linux (or UNIX) distribution, otherwise, stick to Windows specific commands, though in that case, I can't give you much info...
Inspired by beepr, this is the function I'm currently using for these kind of problems :D
work_complete <- function() {
cat("Work complete. Press esc to sound the fanfare!!!\n")
on.exit(beepr::beep(3))
while (TRUE) {
beepr::beep(4)
Sys.sleep(1)
}
}
How about playing some music?
shell.exec("foo/Born.to.be.wild.mp3")
take a look at this package: RPushBullet
An R interface to the Pushbullet messaging service which provides fast
and efficient notifications (and file transfer) between computers,
phones and tablets
RPushbullet is completely free and multi platform. As for your question, you can use this library to send a Push to your browser, but obviously it becomes amazing when you need something than can notify you while you are away.
Moreover, the creator of the R package is the same of the well known Rcpp, Dirk Eddelbuettel. I'd say it's worth a shot!
Do this:
song <- function() {
for(i in 1:2) {
for(i in 1:4) {
for(i in 1:4) {
beep(7)
Sys.sleep(0.25)
beep()
Sys.sleep(0.22)
}
beep(2)
}
beep(11)
}
beep(4)
}
song()
You can jam out to it.
How about using Windows SpeechSynthesizer?
message <- "job done!"
system2(command = "PowerShell",
args = c("-Command",
"\"Add-Type -AssemblyName System.Speech;",
"$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;",
paste0("$speak.Speak('", message, "');\"")
))
This may by nicely used in iterating operations and read something like "First job done", "Second job done" etc.:
say_something <- function(message) {
message <- paste0("$speak.Speak('", message, "');\"")
system2(command = "PowerShell",
args = c("-Command",
"\"Add-Type -AssemblyName System.Speech;",
"$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;",
message
))
}
operations <- c("1st.", "2nd.", "3rd.")
lapply(operations, function(x) say_something(message=paste(x, "job done")))
*Note, that this uses system defaul language settings. The example is based on english lector, it can be changed using SelectVoice method. To check available lectors use:
system2(command = "PowerShell",
args = c("-Command",
"\"Add-Type -AssemblyName System.Speech;",
"$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;",
"$speak.GetInstalledVoices().VoiceInfo")
)
That gives:
Gender : Female
Age : Adult
Name : Microsoft Paulina Desktop
Culture : pl-PL
Id : TTS_MS_PL-PL_PAULINA_11.0
Description : Microsoft Paulina Desktop - Polish
SupportedAudioFormats : {}
AdditionalInfo : {[Age, Adult], [Gender, Female], [Language, 415], [Name, Microsoft Paulina Desktop]...}
Gender : Male
Age : Adult
Name : Microsoft David Desktop
Culture : en-US
Id : TTS_MS_EN-US_DAVID_11.0
Description : Microsoft David Desktop - English (United States)
SupportedAudioFormats : {}
AdditionalInfo : {[Age, Adult], [Gender, Male], [Language, 409], [Name, Microsoft David Desktop]...}
Finally a function to select the lector by his "name" like "David", "Paulina" or "Hazel":
say_something <- function(message , voice) {
voice <- paste0("\"$speak.SelectVoice('Microsoft ", voice, " Desktop');" )
message <- paste0("$speak.Speak('", message, "');\"")
system2(command = "PowerShell",
args = c("-Command",
"\"Add-Type -AssemblyName System.Speech;",
"$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;",
voice,
message
))
}
operations <- c("1st.", "2nd.", "3rd.")
lapply(operations, function(x) say_something(message=paste(x, "job done"), voice="David"))
Dason's answer is great, obviously, because it will work on basically any Windows machine without requiring anything except R itself.
But one thing I have been wondering is how to make these functions actually beep after a code is run.
If you do something like this:
beepR <- function(x, n = 3){
for(i in seq(n)){
system("rundll32 user32.dll,MessageBeep -1")
Sys.sleep(.5)
}
return(x)
}
You can just pipe anything to it and it will return whatever you piped, so you can do like. See the example below.
fa <- psych::fa(x, 1) |> beepR()
I'm using here the native pipe |> that was introduced in R 4.1, but you can use the %>% pipe from the maggitr package if you like; they work the exact same way. Anyway, that will beep as soon as the analysis ends, and the variable fa will contain the results of the factor analysis.
Of course, here I used the beep function that Dason provided you, but you could just as easily add anything where I indicated below.
beepR <- function(x){
# your code here #
return(x)
}
If you wish to add that function every time RStudio opens, refer to RStudio's Managing R with .Rprofile, .Renviron, Rprofile.site, Renviron.site, rsession.conf, and repos.conf to learn how to use a .Rprofile file.
You can use notify-send command:
system("notify-send \"R script finished running\"")
Because of these many ideas, I have created a solution without Internet access, because I work with a VPN client with Windows. So it plays a typical Windows sound, which is usually on any Windows operating system.
#Function with loop, press Esc to stopp
alarm2 <- function(){
while(TRUE){
system("cmd.exe",input="C:/Windows/WinSxS/amd64_microsoft-windows-shell-sounds_31bf3856ad364e35_10.0.17134.1_none_fc93088a1eb3fd11/tada.wav")
Sys.sleep(1)
}
}
Function without loop
alarm3 <- function(){
system("cmd.exe",input="C:/Windows/WinSxS/amd64_microsoft-windows-shell-sounds_31bf3856ad364e35_10.0.17134.1_none_fc93088a1eb3fd11/tada.wav")
Sys.sleep(1)
}
The following code produces a beep and does not depend on a .mp3 or .wav file:
switch(Sys.info()[['sysname']],
Linux = {
system('play -n synth 0.1 tri 1000.0')}
)
Combining some ideas on the thread, I implement this:
options(error = function() {
if (interactive()) {
# require("beepr"); beep(10)
system("mplayer /usr/share/sounds/freedesktop/stereo/dialog-warning.oga ")
system("notify-send -u normal 'R session' 'An error occured!'")
}
})
I regularly use stop() on interactive session like Rstudio, on scripts I am working and want to re-run to a point. This way I can switch to another desktop while waiting. I may test it to '.Rprofile'

Why Function "if ProcessExist" Don't Work in Others Computers

I'm trying to execute an IF ProcessExist.
in my win 10 64bit computer it works, but when i execute in other PC with win 7 or even with win 10. It do not execute.
#AutoIt3Wrapper_UseX64=N
If ProcessExists ("program.exe") Then
MsgBox ("", "Hold", "Test", 10)
Exit
Else
#RequireAdmin
Run(#ComSpec & " /c " & "C:\folder\file.bat", "", #SW_HIDE)
EndIf
Keep getting as if program.exe exist, but it's not.
#RequireAdmin must be on the very top of your script.
I assume it's not working when you compile the executable. It's probably called program.exe and it's finding its own process.
As for the Singleton see this:
_Singleton ( $sOccurrenceName [, $iFlag = 0] )
Enforce a design paradigm where only one instance of the script may be running
Example
#include <Misc.au3>
#include <MsgBoxConstants.au3>
If _Singleton("test", 1) = 0 Then
MsgBox($MB_SYSTEMMODAL, "Warning", "An occurrence of test is already running")
Exit
EndIf
MsgBox($MB_SYSTEMMODAL, "OK", "the first occurrence of test is running")

How to Read * terminated dtmf digits in asterisk

I know Read command gets # terminated dtmf digits. But how can I read dtmf digits terminated by asterisk character "*"?
For example, if I have to enter "092", i press "092*" from keypad.
To modify the behaviour, see apps/app_read.c in the asterisk source directory.
if (tmp[x-1] == '#') {
tmp[x-1] = '\0';
status = "OK";
break;
}
Replace # with *.
You only need to recompile that module:
rm apps/app_read.o apps/app_read.so
make
cp -f apps/app_read.so /lib/asterisk/modules/
service asterisk restart
You have 2 ways here
1) not realible, but can work most of time. Just read one digit at time using AGI getdata or dialplan Read command.
2) create fork of app_read and change # to * in code.
Changing tmp[x-1] == '#' to tmp[x-1] == '*' in apps/app_read.c is necessary but not enough.
You can do these steps:
1. Replace # with * in apps/app_read.c:
// if (tmp[x-1] == '#'){
if (tmp[x-1] == '*'){
tmp[x-1] = '\0';
status = "OK";
break;
}
2. Replace # with * in main/app.c:
//res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
res = ast_readstring_full(c, s, maxlen, to, fto, "*", audiofd, ctrlfd);
//static const char default_acceptdtmf[] = "#";
static const char default_acceptdtmf[] = "*";
//res = ast_readstring(c, s, maxlen, to, fto, "#");
res = ast_readstring(c, s, maxlen, to, fto, "*");
3. Recompile asterisk:
sudo make clean
sudo make
sudo make install
I've done these steps and it worked for me.
You can use both STAR and/or HASH terminated input at the same time. You can do the same without patching asterisk.
Use READ Application as below.
READ(keyPressed,audio-file,maxDigits,t(#,*),maxAttempts,dtmfInputTimeoutSec)
For only STAR terminated inputs, just use t(*) in read application
This t option has announced but will not work in asterisk 16. I didnt test it on another versions.

Is there a way to make R beep/play a sound at the end of a script?

When I run R scripts I go do something else on a different desktop. If I don't check frequently, I never know when something is finished. Is there a way to invoke a beep (like a system beep) or get R to play a sound or notify growl via some code at the end of my script?
I have a package (beepr) with the sole purpose of making notification sounds in R which should work cross-platform. Run the following to install beepr and make a sound:
install.packages("beepr")
library(beepr)
beep()
More info at github: https://github.com/rasmusab/beepr
alarm()
The alarm function. It works by sending \a to the console
On MacOSX you can let the computer speak:
system("say Just finished!")
and you can also change the artificial voice that will speak:
system("say -v Kathy Just finished!")
You can pick any voice that is available on your computer. On Yosemite you can see which voices are installed in System Preferences -> Dictation & Speech -> Text to Speech.
You should have it tweet when it's done: http://cran.r-project.org/web/packages/twitteR/index.html
alarm doesn't work on my Windows machine so I created a function that does actually make noise.
beep <- function(n = 3){
for(i in seq(n)){
system("rundll32 user32.dll,MessageBeep -1")
Sys.sleep(.5)
}
}
This clearly could only work on Windows but I don't guarantee it will even run on an arbitrary Windows computer. I've only tested it on my machine but I figured I'd post it in case anybody has the same problem with alarm that I do.
cat('Hello world!\a')
How about something reasonably OS independent for OSes with GUIs and web-browsers? It even works on RStudio Server!
browseURL('https://www.youtube.com/watch?v=QH2-TGUlwu4')
Not only that, you can also also put some epic music from Youtube when the program is done looping :) (For Ubuntu/Debian:)
system("xdg-open 'http://www.youtube.com/watch?v=9jK-NcRmVcw'")
UPDATE:
With macOS 10.9 (Mavericks) and later, you can post notifications using plain AppleScript:
theTitle <- "A Title"
theMsg <- "A message here"
cmd <- paste("osascript -e ", "'display notification ", '"', theMsg, '"', ' with title ', '"', theTitle, '"', "'", sep='')
system(cmd)
This removes the need to install terminal-notifier, referenced below.
--
I've got terminal-notifier installed on my Mac to get desktop notifications from the command line. You can then wrap up a call to the system() command like this (change the path, obviously):
notify <- function(msgString='Message from R', titleString='Message from R', speakIt=FALSE) {
cmd <- paste('~/terminal-notifier/terminal-notifier.app/Contents/MacOS/terminal-notifier -message ', '"', msgString, '" -title "', titleString, '"', sep='')
system(cmd)
if (speakIt) {
system(paste('say', msgString))
}
}
You can call the function like this
notify("R is done", "Message from R", speakIt=TRUE)
to get a message like this:
Update: Included #VLC's say command.
Please use shell.exec("url") to open some YouTube clip on Windows
Or if you're using GNU/Linux distro and have pcspkr module blacklisted (PC speaker was always annoying me), try combining system with some auditive/visual notification, e.g.
system("aplay -t wav /usr/share/sounds/phone.wav") # for auditive bell (an I mean it literary)
system("zenity --title=\"R script info\" --text=\"Script has finished with zero exit status\" --info") # for GTK dialog
You can check zenity manual if you prefer alert in, say, notification area... But, with system function, you can do pretty much anything: send an email, run some other script, reboot the machine, sudo rm -rf *.*, etc. anything... and I mean it.
But this stands only IF you're running GNU/Linux (or UNIX) distribution, otherwise, stick to Windows specific commands, though in that case, I can't give you much info...
Inspired by beepr, this is the function I'm currently using for these kind of problems :D
work_complete <- function() {
cat("Work complete. Press esc to sound the fanfare!!!\n")
on.exit(beepr::beep(3))
while (TRUE) {
beepr::beep(4)
Sys.sleep(1)
}
}
How about playing some music?
shell.exec("foo/Born.to.be.wild.mp3")
take a look at this package: RPushBullet
An R interface to the Pushbullet messaging service which provides fast
and efficient notifications (and file transfer) between computers,
phones and tablets
RPushbullet is completely free and multi platform. As for your question, you can use this library to send a Push to your browser, but obviously it becomes amazing when you need something than can notify you while you are away.
Moreover, the creator of the R package is the same of the well known Rcpp, Dirk Eddelbuettel. I'd say it's worth a shot!
Do this:
song <- function() {
for(i in 1:2) {
for(i in 1:4) {
for(i in 1:4) {
beep(7)
Sys.sleep(0.25)
beep()
Sys.sleep(0.22)
}
beep(2)
}
beep(11)
}
beep(4)
}
song()
You can jam out to it.
How about using Windows SpeechSynthesizer?
message <- "job done!"
system2(command = "PowerShell",
args = c("-Command",
"\"Add-Type -AssemblyName System.Speech;",
"$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;",
paste0("$speak.Speak('", message, "');\"")
))
This may by nicely used in iterating operations and read something like "First job done", "Second job done" etc.:
say_something <- function(message) {
message <- paste0("$speak.Speak('", message, "');\"")
system2(command = "PowerShell",
args = c("-Command",
"\"Add-Type -AssemblyName System.Speech;",
"$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;",
message
))
}
operations <- c("1st.", "2nd.", "3rd.")
lapply(operations, function(x) say_something(message=paste(x, "job done")))
*Note, that this uses system defaul language settings. The example is based on english lector, it can be changed using SelectVoice method. To check available lectors use:
system2(command = "PowerShell",
args = c("-Command",
"\"Add-Type -AssemblyName System.Speech;",
"$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;",
"$speak.GetInstalledVoices().VoiceInfo")
)
That gives:
Gender : Female
Age : Adult
Name : Microsoft Paulina Desktop
Culture : pl-PL
Id : TTS_MS_PL-PL_PAULINA_11.0
Description : Microsoft Paulina Desktop - Polish
SupportedAudioFormats : {}
AdditionalInfo : {[Age, Adult], [Gender, Female], [Language, 415], [Name, Microsoft Paulina Desktop]...}
Gender : Male
Age : Adult
Name : Microsoft David Desktop
Culture : en-US
Id : TTS_MS_EN-US_DAVID_11.0
Description : Microsoft David Desktop - English (United States)
SupportedAudioFormats : {}
AdditionalInfo : {[Age, Adult], [Gender, Male], [Language, 409], [Name, Microsoft David Desktop]...}
Finally a function to select the lector by his "name" like "David", "Paulina" or "Hazel":
say_something <- function(message , voice) {
voice <- paste0("\"$speak.SelectVoice('Microsoft ", voice, " Desktop');" )
message <- paste0("$speak.Speak('", message, "');\"")
system2(command = "PowerShell",
args = c("-Command",
"\"Add-Type -AssemblyName System.Speech;",
"$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;",
voice,
message
))
}
operations <- c("1st.", "2nd.", "3rd.")
lapply(operations, function(x) say_something(message=paste(x, "job done"), voice="David"))
Dason's answer is great, obviously, because it will work on basically any Windows machine without requiring anything except R itself.
But one thing I have been wondering is how to make these functions actually beep after a code is run.
If you do something like this:
beepR <- function(x, n = 3){
for(i in seq(n)){
system("rundll32 user32.dll,MessageBeep -1")
Sys.sleep(.5)
}
return(x)
}
You can just pipe anything to it and it will return whatever you piped, so you can do like. See the example below.
fa <- psych::fa(x, 1) |> beepR()
I'm using here the native pipe |> that was introduced in R 4.1, but you can use the %>% pipe from the maggitr package if you like; they work the exact same way. Anyway, that will beep as soon as the analysis ends, and the variable fa will contain the results of the factor analysis.
Of course, here I used the beep function that Dason provided you, but you could just as easily add anything where I indicated below.
beepR <- function(x){
# your code here #
return(x)
}
If you wish to add that function every time RStudio opens, refer to RStudio's Managing R with .Rprofile, .Renviron, Rprofile.site, Renviron.site, rsession.conf, and repos.conf to learn how to use a .Rprofile file.
You can use notify-send command:
system("notify-send \"R script finished running\"")
Because of these many ideas, I have created a solution without Internet access, because I work with a VPN client with Windows. So it plays a typical Windows sound, which is usually on any Windows operating system.
#Function with loop, press Esc to stopp
alarm2 <- function(){
while(TRUE){
system("cmd.exe",input="C:/Windows/WinSxS/amd64_microsoft-windows-shell-sounds_31bf3856ad364e35_10.0.17134.1_none_fc93088a1eb3fd11/tada.wav")
Sys.sleep(1)
}
}
Function without loop
alarm3 <- function(){
system("cmd.exe",input="C:/Windows/WinSxS/amd64_microsoft-windows-shell-sounds_31bf3856ad364e35_10.0.17134.1_none_fc93088a1eb3fd11/tada.wav")
Sys.sleep(1)
}
The following code produces a beep and does not depend on a .mp3 or .wav file:
switch(Sys.info()[['sysname']],
Linux = {
system('play -n synth 0.1 tri 1000.0')}
)
Combining some ideas on the thread, I implement this:
options(error = function() {
if (interactive()) {
# require("beepr"); beep(10)
system("mplayer /usr/share/sounds/freedesktop/stereo/dialog-warning.oga ")
system("notify-send -u normal 'R session' 'An error occured!'")
}
})
I regularly use stop() on interactive session like Rstudio, on scripts I am working and want to re-run to a point. This way I can switch to another desktop while waiting. I may test it to '.Rprofile'

How do I determine if a terminal is color-capable?

I would like to change a program to automatically detect whether a terminal is color-capable or not, so when I run said program from within a non-color capable terminal (say M-x shell in (X)Emacs), color is automatically turned off.
I don't want to hardcode the program to detect TERM={emacs,dumb}.
I am thinking that termcap/terminfo should be able to help with this, but so far I've only managed to cobble together this (n)curses-using snippet of code, which fails badly when it can't find the terminal:
#include <stdlib.h>
#include <curses.h>
int main(void) {
int colors=0;
initscr();
start_color();
colors=has_colors() ? 1 : 0;
endwin();
printf(colors ? "YES\n" : "NO\n");
exit(0);
}
I.e. I get this:
$ gcc -Wall -lncurses -o hep hep.c
$ echo $TERM
xterm
$ ./hep
YES
$ export TERM=dumb
$ ./hep
NO
$ export TERM=emacs
$ ./hep
Error opening terminal: emacs.
$
which is... suboptimal.
A friend pointed me towards tput(1), and I cooked up this solution:
#!/bin/sh
# ack-wrapper - use tput to try and detect whether the terminal is
# color-capable, and call ack-grep accordingly.
OPTION='--nocolor'
COLORS=$(tput colors 2> /dev/null)
if [ $? = 0 ] && [ $COLORS -gt 2 ]; then
OPTION=''
fi
exec ack-grep $OPTION "$#"
which works for me. It would be great if I had a way to integrate it into ack, though.
You almost had it, except that you need to use the lower-level curses function setupterm instead of initscr. setupterm just performs enough initialization to read terminfo data, and if you pass in a pointer to an error result value (the last argument) it will return an error value instead of emitting error messages and exiting (the default behavior for initscr).
#include <stdlib.h>
#include <curses.h>
int main(void) {
char *term = getenv("TERM");
int erret = 0;
if (setupterm(NULL, 1, &erret) == ERR) {
char *errmsg = "unknown error";
switch (erret) {
case 1: errmsg = "terminal is hardcopy, cannot be used for curses applications"; break;
case 0: errmsg = "terminal could not be found, or not enough information for curses applications"; break;
case -1: errmsg = "terminfo entry could not be found"; break;
}
printf("Color support for terminal \"%s\" unknown (error %d: %s).\n", term, erret, errmsg);
exit(1);
}
bool colors = has_colors();
printf("Terminal \"%s\" %s colors.\n", term, colors ? "has" : "does not have");
return 0;
}
Additional information about using setupterm is available in the curs_terminfo(3X) man page (x-man-page://3x/curs_terminfo) and Writing Programs with NCURSES.
Look up the terminfo(5) entry for the terminal type and check the Co (max_colors) entry. That's how many colors the terminal supports.

Resources