I have a thermal printer(ESC/POS) already configured on my linux machine and using the terminal command (as root) I can make it print:
echo "Hello!" > /dev/usb/lp0
However, doing the same procedure in golang nothing happens:
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("Hello Would!")
f, err := os.Open("/dev/usb/lp0")
if err != nil {
panic(err)
}
defer f.Close()
f.Write([]byte("Hello world!"))
}
What am I doing wrong?
As described in the documentation os.Open() opens a file read-only.
You would have discovered the problem if you had checked the return from your Write() call. Always check errors. Don't ignore them, even in tiny programs like this; they will give you a clue as to what is wrong.
To fix the problem, open the device special for writing with os.OpenFile().
f, err := os.OpenFile("/dev/usb/lp0", os.O_RDWR, 0)
Related
I have a small issue here when I try to run this code
package main
import (
"fmt"
"os/exec"
)
func main() {
out, err := exec.Command("./node_modules/.bin/solcjs", "--version").Output()
if err != nil {
panic(err)
}
fmt.Println(out)
}
This code will get solcjs version from ./node_modules/.bin/solcjs.
But, the code return an error telling me that the file/folder doesn't exist, and I try the command ./node_modules/.bin/solcjs --version my self and it work perfectly. Why when i use go it show error?
You probably need to mention the full path of the solcjs file.
Use snippet below to take the current working directory and then add this path before /node_modules/.bin/solcjs:
mydir, _ := os.Getwd()
file_full_path := mydir + "/node_modules/.bin/solcjs"
out, err := exec.Command(file_full_path, "--version").Output()
I use go-daemon library to fork process and run it in background. And I need to restart the daemon process after update performed from within http handler.
The handler code is
func httpUpdate(w http.ResponseWriter, req *http.Request) {
if !isPost(req.Method) {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
if checkAuth(req) != 200 {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
return
}
log.Println("INFO: Update request, checking for update...")
var err = doUpdate(UPDATE_URL, nil, false)
if !isError(err) {
log.Println("INFO: Update successful, exit")
var system = RealSystem{}
system.Run(fmt.Sprintf("(sleep 0.3s && %s start &> /test/extra.log)&disown", appFilename()))
system.Exit(0)
return
}
w.WriteHeader(http.StatusNoContent)
}
doUpdate() returns nil if successfully replaced the executable file. RealSystem is just wrapper for exec.Command and os.Exit(). appFilename() is the executable file name. The command to start app is /path/to/app start.
I see that new process starts, but executing Context::Reborn() fails with EOF error. Looks like some intrinsic pipes used as implementation details fail with EOF (may be...).
What would be the reason? Or may be there is a better way of doing that?
For now everything happens inside docker container in the "context" of e2e test if it matters. I spent hours trying to make it work but with no success.
I assume you mean restarting the currently running Go binary. You can use a syscall for unix-based systems, and use an exec.Command for Windows.
func RestartSelf() error {
self, err := osext.Executable()
if err != nil {
return err
}
args := os.Args
env := os.Environ()
// Windows does not support exec syscall.
if runtime.GOOS == "windows" {
cmd := exec.Command(self, args[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
cmd.Env = env
err := cmd.Run()
if err == nil {
os.Exit(0)
}
return err
}
return syscall.Exec(self, args, env)
}
The issue is specific to the library. Spawn new self instance from within child process is not a problem for the system, but for that library.
To achieve this it's necessary to execute something like that.
Note the _GO_DAEMON=0 variable set to zero. This makes library follow parent control flow.
var cmd = exec.Command("bash", "-c", fmt.Sprintf("sleep 0.5s; _GO_DAEMON=0 %s start", appFilename()))
var err = cmd.Start()
Also it was necessary to make small changes to the original library. Here is the fork.
I am searching for a way to answer to a shell password prompt in golang.
like :
bussiere#kus:~/Workspace/rteest$ ./passwordtest.sh
Password :
I would like to enter the password automatically with my token in golang after launching a shell command / script ...
I've made some script that get a one time token with mfa if everything is ok (in golang). So i need to enter the tempory token to a linux password prompt.
I know that there is the expect command but i would like to compile my program to embed it and have minimal depency.
Thanks and regards
edit thks to #nevermore i've tried this (but it doesn't work) : https://play.golang.org/p/Ffm3q5h636
package main
import (
"os/exec"
"fmt"
"log"
"io"
)
func main() {
cmdb := "git"
args := "clone https://bb#gitlab.com/bb/fzgs.git"
cmd := exec.Command(cmdb, args)
stdin, err := cmd.StdinPipe()
if err != nil {
log.Fatal(err)
}
go func() {
defer stdin.Close()
io.WriteString(stdin, "QSRDFGHJfZERTYU")
}()
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", out)
}
it gives me this :
2017/05/12 20:42:36 exit status 1
exit status 1
edit bis :
cmdb := "git"
args := "https://bb#gitlab.com/bb/fzgs.git"
cmd := exec.Command(cmdb, "clone", args)
it asks for the password :
Password for 'https://bb#gitlab.com':
The problem is that you are trying to send the password before Git asks you
to do so.
And the way Git asks for password depends on whether credential helper is set. If the credential helper is not set, or doesn't return a password, the user is asked for input.
Solution #1: Include Password into URI
In most cases (at least with Github and Bitbucket) the Git server accepts
credentials passed via HTTPS URI, e.g. https://user:password#domain.com/repo.git.
cmd := exec.Command("git", "clone", "https://bb:PASSWORD#gitlab.com/bb/fzgs.git")
env := os.Environ()
env = append(env, "GIT_ASKPASS=")
cmd.Env = env
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
Solution #2: Custom Credential Helper
Another way is to make a credential helper script, e.g.:
#!/bin/bash -
printf '%s\n' 'YOUR_PASSWORD'
and pass it via GIT_ASKPASS:
cmd := exec.Command("git", "clone", "https://bb#gitlab.com/bb/fzgs.git")
env := os.Environ()
env = append(env, "GIT_ASKPASS=/path/to/fzgs-askpass.sh")
cmd.Env = env
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
If a user is asked for a password in their shell, you can use golang to write to the io.Writer that is os.Stdin
Properly passing data on stdin to a command and receiving data from stdout of that command in golang
os.Stdin is a os.File created by
NewFile(uintptr(syscall.Stdin), "/dev/stdin")
And the password prompt will be reading from this file
You can execute ./passwordtest.sh as in your question, and then write the password to os.Stdin, and the bash script should accept the bytes written by golang as the password.
Alternatively is actually a method for this in the exec package for the Cmd type.
Use cmd to execute your shell script
Input the password using stdin, or cmd.StdinPip()
Read the shells output using cmd.CombinedOutput()
Cmd represents an external command being prepared or run.
https://golang.org/pkg/os/exec/#Cmd.StdinPipe
cmd := exec.Command("cat")
stdin, err := cmd.StdinPipe()
if err != nil {
log.Fatal(err)
}
go func() {
defer stdin.Close()
io.WriteString(stdin, "values written to stdin are passed to cmd's standard input")
}()
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", out)
StdinPipe returns a pipe that will be connected to the command's standard input when the command starts. The pipe will be closed automatically after Wait sees the command exit. A caller need only call Close to force the pipe to close sooner. For example, if the command being run will not exit until standard input is closed, the caller must close the pipe.
Also, your cmd arguments shouldn't combine clone and the url, try instead
cmd := exec.Command(cmdb, "clone", url)
I am trying to figure out how to launch an external editor from within a Go program, wait for the user to close the editor, and then continue execution of the program. Based on this SO answer, I currently have this code:
package main
import (
"log"
"os"
"os/exec"
)
func main() {
fpath := os.TempDir() + "/thetemporaryfile.txt"
f, err := os.Create(fpath)
if err != nil {
log.Printf("1")
log.Fatal(err)
}
f.Close()
cmd := exec.Command("vim", fpath)
err = cmd.Start()
if err != nil {
log.Printf("2")
log.Fatal(err)
}
err = cmd.Wait()
if err != nil {
log.Printf("Error while editing. Error: %v\n", err)
} else {
log.Printf("Successfully edited.")
}
}
When I run the program, I get this:
chris#DPC3:~/code/go/src/launcheditor$ go run launcheditor.go
2012/08/23 10:50:37 Error while editing. Error: exit status 1
chris#DPC3:~/code/go/src/launcheditor$
I have also tried using exec.Run() instead of exec.Start(), but that doesn't seem to work either (though it doesn't fail at the same place).
I can get it to work if I use Gvim instead of Vim, but it refuses to work with both Vim and nano. I think it's related to Vim and nano running inside the terminal emulator instead of creating an external window.
Apparently, you have to set Stdin, Stdout and Stderr on the Cmd object to os.Std(in|out|err). Like this (assuming that the object is called cmd):
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
Credit for solving this goes to the guys on #go-nuts on freenode.
This works for me but it has the disadvantage of opening another terminal (which will automatically close after edition) :
cmd := exec.Command("/usr/bin/xterm", "-e", "vim "+fpath)
Here in cmd := exec.Command("vim", fpath), you're doing more or less:
$ PATH= vim foo.txt
bash: vim: No such file or directory
$
Shell uses the PATH environment variable, exec.Command does not. You have to lookup the vim binary and pass its full path to exec.Command. exec.LookPath does that for you.
I have an application, let's call it myapp.exe, which is dual-mode console/GUI, built as /SUBSYSTEM:WINDOWS (There's a tiny 3KB shim myapp.com to cause cmd.exe to wait to display the new prompt.)
If I launch from a command prompt:
myapp -> cmd.exe runs myapp.com which runs myapp.exe. stdout is initially a detached console, by using AttachConsole and freopen("CONOUT$", "w", stdout) my output appears in the command box. OK
myapp.exe -> cmd.exe displays the prompt too early (known problem), otherwise same as previous. Not a normal usage scenario.
myapp > log -> stdout is a file, normal use of std::cout ends up in the file. OK
If I launch from Windows explorer:
myapp.com -> console is created, stdout is console, output goes into console. Same result as using /SUBSYSTEM:CONSOLE for the entire program, except that I've added a pause when myapp.com is the only process in the console. Not a normal usage scenario.
myapp.exe -> stdout is a NULL handle, I detect this and hook std::cout to a GUI. OK
If I launch from Matlab shell:
system('myapp') or system('myapp.com') or system('myapp.exe') -> For all three variations, stdout is piped to MatLab. OK
If I launch from a cygwin bash shell:
./myapp.com -> Just like launch from cmd.exe, the output appears in the command box. OK
./myapp -> (bash finds ./myapp.exe). This is the broken case. stdout is a non-NULL handle but output goes nowhere. This is the normal situation for running the program from bash and needs to be fixed!
./myapp > log -> Just like launch from cmd.exe with file redirection. OK
./myapp | cat -> Similar to file redirection, except output ends up on the console window. OK
Does anybody know what cygwin sets as stdout when launching a /SUBSYSTEM:WINDOWS process and how I can bind std::cout to it? Or at least tell me how to find out what kind of handle I'm getting back from GetStdHandle(STD_OUTPUT_HANDLE)?
My program is written with Visual C++ 2010, without /clr, in case that matters in any way. OS is Windows 7 64-bit.
EDIT: Additional information requested.
CYGWIN environment variable is empty (or non-existent).
GetFileType() returns FILE_TYPE_UNKNOWN. GetLastError() returns 6 (ERROR_INVALID_HANDLE). It doesn't matter whether I check before or after calling AttachConsole().
However, if I simply ignore the invalid handle and freopen("CONOUT$", "w", stdout) then everything works great. I was just missing a way to distinguish between (busted) console output and file redirection, and GetFileType() provided that.
EDIT: Final code:
bool is_console(HANDLE h)
{
if (!h) return false;
::AttachConsole(ATTACH_PARENT_PROCESS);
if (FILE_TYPE_UNKNOWN == ::GetFileType(h) && ERROR_INVALID_HANDLE == GetLastError()) {
/* workaround cygwin brokenness */
h = ::CreateFile(_T("CONOUT$"), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (h) {
::CloseHandle(h);
return true;
}
}
CONSOLE_FONT_INFO cfi;
return ::GetCurrentConsoleFont(h, FALSE, &cfi) != 0;
}
bool init( void )
{
HANDLE out = ::GetStdHandle(STD_OUTPUT_HANDLE);
if (out) {
/* stdout exists, might be console, file, or pipe */
if (is_console(out)) {
#pragma warning(push)
#pragma warning(disable: 4996)
freopen("CONOUT$", "w", stdout);
#pragma warning(pop)
}
//std::stringstream msg;
//DWORD result = ::GetFileType(out);
//DWORD lasterror = ::GetLastError();
//msg << result << std::ends;
//::MessageBoxA(NULL, msg.str().c_str(), "GetFileType", MB_OK);
//if (result == FILE_TYPE_UNKNOWN) {
// msg.str(std::string());
// msg << lasterror << std::ends;
// ::MessageBoxA(NULL, msg.str().c_str(), "GetLastError", MB_OK);
//}
return true;
}
else {
/* no text-mode stdout, launch GUI (actual code removed) */
}
}
The GetFileType() function allows to distinguish between some types of handles, in particular consoles, pipes, files, and broken handles.