aboutsummaryrefslogtreecommitdiffstats
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/ethkey/README.md41
-rw-r--r--cmd/ethkey/generate.go117
-rw-r--r--cmd/ethkey/inspect.go74
-rw-r--r--cmd/ethkey/main.go70
-rw-r--r--cmd/ethkey/message.go148
-rw-r--r--cmd/ethkey/utils.go83
-rw-r--r--cmd/evm/json_logger.go10
-rw-r--r--cmd/faucet/faucet.go7
-rw-r--r--cmd/utils/fdlimit_freebsd.go10
-rw-r--r--cmd/utils/fdlimit_test.go12
-rw-r--r--cmd/utils/fdlimit_unix.go10
-rw-r--r--cmd/utils/fdlimit_windows.go6
12 files changed, 581 insertions, 7 deletions
diff --git a/cmd/ethkey/README.md b/cmd/ethkey/README.md
new file mode 100644
index 000000000..cf72ba43d
--- /dev/null
+++ b/cmd/ethkey/README.md
@@ -0,0 +1,41 @@
+ethkey
+======
+
+ethkey is a simple command-line tool for working with Ethereum keyfiles.
+
+
+# Usage
+
+### `ethkey generate`
+
+Generate a new keyfile.
+If you want to use an existing private key to use in the keyfile, it can be
+specified by setting `--privatekey` with the location of the file containing the
+private key.
+
+
+### `ethkey inspect <keyfile>`
+
+Print various information about the keyfile.
+Private key information can be printed by using the `--private` flag;
+make sure to use this feature with great caution!
+
+
+### `ethkey sign <keyfile> <message/file>`
+
+Sign the message with a keyfile.
+It is possible to refer to a file containing the message.
+
+
+### `ethkey verify <address> <signature> <message/file>`
+
+Verify the signature of the message.
+It is possible to refer to a file containing the message.
+
+
+## Passphrases
+
+For every command that uses a keyfile, you will be prompted to provide the
+passphrase for decrypting the keyfile. To avoid this message, it is possible
+to pass the passphrase by using the `--passphrase` flag pointing to a file that
+contains the passphrase.
diff --git a/cmd/ethkey/generate.go b/cmd/ethkey/generate.go
new file mode 100644
index 000000000..dee0e9d70
--- /dev/null
+++ b/cmd/ethkey/generate.go
@@ -0,0 +1,117 @@
+package main
+
+import (
+ "crypto/ecdsa"
+ "crypto/rand"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ "github.com/ethereum/go-ethereum/accounts/keystore"
+ "github.com/ethereum/go-ethereum/cmd/utils"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/pborman/uuid"
+ "gopkg.in/urfave/cli.v1"
+)
+
+type outputGenerate struct {
+ Address string
+ AddressEIP55 string
+}
+
+var commandGenerate = cli.Command{
+ Name: "generate",
+ Usage: "generate new keyfile",
+ ArgsUsage: "[ <keyfile> ]",
+ Description: `
+Generate a new keyfile.
+If you want to use an existing private key to use in the keyfile, it can be
+specified by setting --privatekey with the location of the file containing the
+private key.`,
+ Flags: []cli.Flag{
+ passphraseFlag,
+ jsonFlag,
+ cli.StringFlag{
+ Name: "privatekey",
+ Usage: "the file from where to read the private key to " +
+ "generate a keyfile for",
+ },
+ },
+ Action: func(ctx *cli.Context) error {
+ // Check if keyfile path given and make sure it doesn't already exist.
+ keyfilepath := ctx.Args().First()
+ if keyfilepath == "" {
+ keyfilepath = defaultKeyfileName
+ }
+ if _, err := os.Stat(keyfilepath); err == nil {
+ utils.Fatalf("Keyfile already exists at %s.", keyfilepath)
+ } else if !os.IsNotExist(err) {
+ utils.Fatalf("Error checking if keyfile exists: %v", err)
+ }
+
+ var privateKey *ecdsa.PrivateKey
+
+ // First check if a private key file is provided.
+ privateKeyFile := ctx.String("privatekey")
+ if privateKeyFile != "" {
+ privateKeyBytes, err := ioutil.ReadFile(privateKeyFile)
+ if err != nil {
+ utils.Fatalf("Failed to read the private key file '%s': %v",
+ privateKeyFile, err)
+ }
+
+ pk, err := crypto.HexToECDSA(string(privateKeyBytes))
+ if err != nil {
+ utils.Fatalf(
+ "Could not construct ECDSA private key from file content: %v",
+ err)
+ }
+ privateKey = pk
+ }
+
+ // If not loaded, generate random.
+ if privateKey == nil {
+ pk, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
+ if err != nil {
+ utils.Fatalf("Failed to generate random private key: %v", err)
+ }
+ privateKey = pk
+ }
+
+ // Create the keyfile object with a random UUID.
+ id := uuid.NewRandom()
+ key := &keystore.Key{
+ Id: id,
+ Address: crypto.PubkeyToAddress(privateKey.PublicKey),
+ PrivateKey: privateKey,
+ }
+
+ // Encrypt key with passphrase.
+ passphrase := getPassPhrase(ctx, true)
+ keyjson, err := keystore.EncryptKey(key, passphrase,
+ keystore.StandardScryptN, keystore.StandardScryptP)
+ if err != nil {
+ utils.Fatalf("Error encrypting key: %v", err)
+ }
+
+ // Store the file to disk.
+ if err := os.MkdirAll(filepath.Dir(keyfilepath), 0700); err != nil {
+ utils.Fatalf("Could not create directory %s", filepath.Dir(keyfilepath))
+ }
+ if err := ioutil.WriteFile(keyfilepath, keyjson, 0600); err != nil {
+ utils.Fatalf("Failed to write keyfile to %s: %v", keyfilepath, err)
+ }
+
+ // Output some information.
+ out := outputGenerate{
+ Address: key.Address.Hex(),
+ }
+ if ctx.Bool(jsonFlag.Name) {
+ mustPrintJSON(out)
+ } else {
+ fmt.Println("Address: ", out.Address)
+ }
+ return nil
+ },
+}
diff --git a/cmd/ethkey/inspect.go b/cmd/ethkey/inspect.go
new file mode 100644
index 000000000..8a7aeef84
--- /dev/null
+++ b/cmd/ethkey/inspect.go
@@ -0,0 +1,74 @@
+package main
+
+import (
+ "encoding/hex"
+ "fmt"
+ "io/ioutil"
+
+ "github.com/ethereum/go-ethereum/accounts/keystore"
+ "github.com/ethereum/go-ethereum/cmd/utils"
+ "github.com/ethereum/go-ethereum/crypto"
+ "gopkg.in/urfave/cli.v1"
+)
+
+type outputInspect struct {
+ Address string
+ PublicKey string
+ PrivateKey string
+}
+
+var commandInspect = cli.Command{
+ Name: "inspect",
+ Usage: "inspect a keyfile",
+ ArgsUsage: "<keyfile>",
+ Description: `
+Print various information about the keyfile.
+Private key information can be printed by using the --private flag;
+make sure to use this feature with great caution!`,
+ Flags: []cli.Flag{
+ passphraseFlag,
+ jsonFlag,
+ cli.BoolFlag{
+ Name: "private",
+ Usage: "include the private key in the output",
+ },
+ },
+ Action: func(ctx *cli.Context) error {
+ keyfilepath := ctx.Args().First()
+
+ // Read key from file.
+ keyjson, err := ioutil.ReadFile(keyfilepath)
+ if err != nil {
+ utils.Fatalf("Failed to read the keyfile at '%s': %v", keyfilepath, err)
+ }
+
+ // Decrypt key with passphrase.
+ passphrase := getPassPhrase(ctx, false)
+ key, err := keystore.DecryptKey(keyjson, passphrase)
+ if err != nil {
+ utils.Fatalf("Error decrypting key: %v", err)
+ }
+
+ // Output all relevant information we can retrieve.
+ showPrivate := ctx.Bool("private")
+ out := outputInspect{
+ Address: key.Address.Hex(),
+ PublicKey: hex.EncodeToString(
+ crypto.FromECDSAPub(&key.PrivateKey.PublicKey)),
+ }
+ if showPrivate {
+ out.PrivateKey = hex.EncodeToString(crypto.FromECDSA(key.PrivateKey))
+ }
+
+ if ctx.Bool(jsonFlag.Name) {
+ mustPrintJSON(out)
+ } else {
+ fmt.Println("Address: ", out.Address)
+ fmt.Println("Public key: ", out.PublicKey)
+ if showPrivate {
+ fmt.Println("Private key: ", out.PrivateKey)
+ }
+ }
+ return nil
+ },
+}
diff --git a/cmd/ethkey/main.go b/cmd/ethkey/main.go
new file mode 100644
index 000000000..b9b7a18e0
--- /dev/null
+++ b/cmd/ethkey/main.go
@@ -0,0 +1,70 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of go-ethereum.
+//
+// go-ethereum 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.
+//
+// go-ethereum 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 go-ethereum. If not, see <http://www.gnu.org/licenses/>.
+
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/ethereum/go-ethereum/cmd/utils"
+ "gopkg.in/urfave/cli.v1"
+)
+
+const (
+ defaultKeyfileName = "keyfile.json"
+)
+
+var (
+ gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags)
+
+ app *cli.App // the main app instance
+)
+
+var ( // Commonly used command line flags.
+ passphraseFlag = cli.StringFlag{
+ Name: "passwordfile",
+ Usage: "the file that contains the passphrase for the keyfile",
+ }
+
+ jsonFlag = cli.BoolFlag{
+ Name: "json",
+ Usage: "output JSON instead of human-readable format",
+ }
+
+ messageFlag = cli.StringFlag{
+ Name: "message",
+ Usage: "the file that contains the message to sign/verify",
+ }
+)
+
+// Configure the app instance.
+func init() {
+ app = utils.NewApp(gitCommit, "an Ethereum key manager")
+ app.Commands = []cli.Command{
+ commandGenerate,
+ commandInspect,
+ commandSignMessage,
+ commandVerifyMessage,
+ }
+}
+
+func main() {
+ if err := app.Run(os.Args); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+}
diff --git a/cmd/ethkey/message.go b/cmd/ethkey/message.go
new file mode 100644
index 000000000..ae6b6552d
--- /dev/null
+++ b/cmd/ethkey/message.go
@@ -0,0 +1,148 @@
+package main
+
+import (
+ "encoding/hex"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/accounts/keystore"
+ "github.com/ethereum/go-ethereum/cmd/utils"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
+ "gopkg.in/urfave/cli.v1"
+)
+
+type outputSign struct {
+ Signature string
+}
+
+var commandSignMessage = cli.Command{
+ Name: "signmessage",
+ Usage: "sign a message",
+ ArgsUsage: "<keyfile> <message/file>",
+ Description: `
+Sign the message with a keyfile.
+It is possible to refer to a file containing the message.`,
+ Flags: []cli.Flag{
+ passphraseFlag,
+ jsonFlag,
+ },
+ Action: func(ctx *cli.Context) error {
+ keyfilepath := ctx.Args().First()
+ message := []byte(ctx.Args().Get(1))
+
+ // Load the keyfile.
+ keyjson, err := ioutil.ReadFile(keyfilepath)
+ if err != nil {
+ utils.Fatalf("Failed to read the keyfile at '%s': %v",
+ keyfilepath, err)
+ }
+
+ // Decrypt key with passphrase.
+ passphrase := getPassPhrase(ctx, false)
+ key, err := keystore.DecryptKey(keyjson, passphrase)
+ if err != nil {
+ utils.Fatalf("Error decrypting key: %v", err)
+ }
+
+ if len(message) == 0 {
+ utils.Fatalf("A message must be provided")
+ }
+ // Read message if file.
+ if _, err := os.Stat(string(message)); err == nil {
+ message, err = ioutil.ReadFile(string(message))
+ if err != nil {
+ utils.Fatalf("Failed to read the message file: %v", err)
+ }
+ }
+
+ signature, err := crypto.Sign(signHash(message), key.PrivateKey)
+ if err != nil {
+ utils.Fatalf("Failed to sign message: %v", err)
+ }
+
+ out := outputSign{
+ Signature: hex.EncodeToString(signature),
+ }
+ if ctx.Bool(jsonFlag.Name) {
+ mustPrintJSON(out)
+ } else {
+ fmt.Println("Signature: ", out.Signature)
+ }
+ return nil
+ },
+}
+
+type outputVerify struct {
+ Success bool
+ RecoveredAddress string
+ RecoveredPublicKey string
+}
+
+var commandVerifyMessage = cli.Command{
+ Name: "verifymessage",
+ Usage: "verify the signature of a signed message",
+ ArgsUsage: "<address> <signature> <message/file>",
+ Description: `
+Verify the signature of the message.
+It is possible to refer to a file containing the message.`,
+ Flags: []cli.Flag{
+ jsonFlag,
+ },
+ Action: func(ctx *cli.Context) error {
+ addressStr := ctx.Args().First()
+ signatureHex := ctx.Args().Get(1)
+ message := []byte(ctx.Args().Get(2))
+
+ // Determine whether it is a keyfile, public key or address.
+ if !common.IsHexAddress(addressStr) {
+ utils.Fatalf("Invalid address: %s", addressStr)
+ }
+ address := common.HexToAddress(addressStr)
+
+ signature, err := hex.DecodeString(signatureHex)
+ if err != nil {
+ utils.Fatalf("Signature encoding is not hexadecimal: %v", err)
+ }
+
+ if len(message) == 0 {
+ utils.Fatalf("A message must be provided")
+ }
+ // Read message if file.
+ if _, err := os.Stat(string(message)); err == nil {
+ message, err = ioutil.ReadFile(string(message))
+ if err != nil {
+ utils.Fatalf("Failed to read the message file: %v", err)
+ }
+ }
+
+ recoveredPubkey, err := crypto.SigToPub(signHash(message), signature)
+ if err != nil || recoveredPubkey == nil {
+ utils.Fatalf("Signature verification failed: %v", err)
+ }
+ recoveredPubkeyBytes := crypto.FromECDSAPub(recoveredPubkey)
+ recoveredAddress := crypto.PubkeyToAddress(*recoveredPubkey)
+
+ success := address == recoveredAddress
+
+ out := outputVerify{
+ Success: success,
+ RecoveredPublicKey: hex.EncodeToString(recoveredPubkeyBytes),
+ RecoveredAddress: strings.ToLower(recoveredAddress.Hex()),
+ }
+ if ctx.Bool(jsonFlag.Name) {
+ mustPrintJSON(out)
+ } else {
+ if out.Success {
+ fmt.Println("Signature verification successful!")
+ } else {
+ fmt.Println("Signature verification failed!")
+ }
+ fmt.Println("Recovered public key: ", out.RecoveredPublicKey)
+ fmt.Println("Recovered address: ", out.RecoveredAddress)
+ }
+ return nil
+ },
+}
diff --git a/cmd/ethkey/utils.go b/cmd/ethkey/utils.go
new file mode 100644
index 000000000..0e563bf92
--- /dev/null
+++ b/cmd/ethkey/utils.go
@@ -0,0 +1,83 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of go-ethereum.
+//
+// go-ethereum 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.
+//
+// go-ethereum 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 go-ethereum. If not, see <http://www.gnu.org/licenses/>.
+
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/cmd/utils"
+ "github.com/ethereum/go-ethereum/console"
+ "github.com/ethereum/go-ethereum/crypto"
+ "gopkg.in/urfave/cli.v1"
+)
+
+// getPassPhrase obtains a passphrase given by the user. It first checks the
+// --passphrase command line flag and ultimately prompts the user for a
+// passphrase.
+func getPassPhrase(ctx *cli.Context, confirmation bool) string {
+ // Look for the --passphrase flag.
+ passphraseFile := ctx.String(passphraseFlag.Name)
+ if passphraseFile != "" {
+ content, err := ioutil.ReadFile(passphraseFile)
+ if err != nil {
+ utils.Fatalf("Failed to read passphrase file '%s': %v",
+ passphraseFile, err)
+ }
+ return strings.TrimRight(string(content), "\r\n")
+ }
+
+ // Otherwise prompt the user for the passphrase.
+ passphrase, err := console.Stdin.PromptPassword("Passphrase: ")
+ if err != nil {
+ utils.Fatalf("Failed to read passphrase: %v", err)
+ }
+ if confirmation {
+ confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ")
+ if err != nil {
+ utils.Fatalf("Failed to read passphrase confirmation: %v", err)
+ }
+ if passphrase != confirm {
+ utils.Fatalf("Passphrases do not match")
+ }
+ }
+ return passphrase
+}
+
+// signHash is a helper function that calculates a hash for the given message
+// that can be safely used to calculate a signature from.
+//
+// The hash is calulcated as
+// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
+//
+// This gives context to the signed message and prevents signing of transactions.
+func signHash(data []byte) []byte {
+ msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data)
+ return crypto.Keccak256([]byte(msg))
+}
+
+// mustPrintJSON prints the JSON encoding of the given object and
+// exits the program with an error message when the marshaling fails.
+func mustPrintJSON(jsonObject interface{}) {
+ str, err := json.MarshalIndent(jsonObject, "", " ")
+ if err != nil {
+ utils.Fatalf("Failed to marshal JSON object: %v", err)
+ }
+ fmt.Println(string(str))
+}
diff --git a/cmd/evm/json_logger.go b/cmd/evm/json_logger.go
index eb7b0c466..47daf7dbb 100644
--- a/cmd/evm/json_logger.go
+++ b/cmd/evm/json_logger.go
@@ -19,6 +19,7 @@ package main
import (
"encoding/json"
"io"
+ "math/big"
"time"
"github.com/ethereum/go-ethereum/common"
@@ -35,6 +36,10 @@ func NewJSONLogger(cfg *vm.LogConfig, writer io.Writer) *JSONLogger {
return &JSONLogger{json.NewEncoder(writer), cfg}
}
+func (l *JSONLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error {
+ return nil
+}
+
// CaptureState outputs state information on the logger.
func (l *JSONLogger) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error {
log := vm.StructLog{
@@ -56,6 +61,11 @@ func (l *JSONLogger) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cos
return l.encoder.Encode(log)
}
+// CaptureFault outputs state information on the logger.
+func (l *JSONLogger) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error {
+ return nil
+}
+
// CaptureEnd is triggered at end of execution.
func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error {
type endLog struct {
diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go
index 5f16f2978..75ec124c1 100644
--- a/cmd/faucet/faucet.go
+++ b/cmd/faucet/faucet.go
@@ -21,7 +21,6 @@ package main
import (
"bytes"
- "compress/zlib"
"context"
"encoding/json"
"errors"
@@ -698,11 +697,7 @@ func authTwitter(url string) (string, string, common.Address, error) {
}
defer res.Body.Close()
- reader, err := zlib.NewReader(res.Body)
- if err != nil {
- return "", "", common.Address{}, err
- }
- body, err := ioutil.ReadAll(reader)
+ body, err := ioutil.ReadAll(res.Body)
if err != nil {
return "", "", common.Address{}, err
}
diff --git a/cmd/utils/fdlimit_freebsd.go b/cmd/utils/fdlimit_freebsd.go
index 4cb5013c8..f9ed8937e 100644
--- a/cmd/utils/fdlimit_freebsd.go
+++ b/cmd/utils/fdlimit_freebsd.go
@@ -52,3 +52,13 @@ func getFdLimit() (int, error) {
}
return int(limit.Cur), nil
}
+
+// getFdMaxLimit retrieves the maximum number of file descriptors this process is
+// allowed to request for itself.
+func getFdMaxLimit() (int, error) {
+ var limit syscall.Rlimit
+ if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+ return 0, err
+ }
+ return int(limit.Max), nil
+}
diff --git a/cmd/utils/fdlimit_test.go b/cmd/utils/fdlimit_test.go
index 0a950a6c9..48489cf4c 100644
--- a/cmd/utils/fdlimit_test.go
+++ b/cmd/utils/fdlimit_test.go
@@ -16,12 +16,22 @@
package utils
-import "testing"
+import (
+ "fmt"
+ "testing"
+)
// TestFileDescriptorLimits simply tests whether the file descriptor allowance
// per this process can be retrieved.
func TestFileDescriptorLimits(t *testing.T) {
target := 4096
+ hardlimit, err := getFdMaxLimit()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if hardlimit < target {
+ t.Skip(fmt.Sprintf("system limit is less than desired test target: %d < %d", hardlimit, target))
+ }
if limit, err := getFdLimit(); err != nil || limit <= 0 {
t.Fatalf("failed to retrieve file descriptor limit (%d): %v", limit, err)
diff --git a/cmd/utils/fdlimit_unix.go b/cmd/utils/fdlimit_unix.go
index 08e153bbd..c08d1fab0 100644
--- a/cmd/utils/fdlimit_unix.go
+++ b/cmd/utils/fdlimit_unix.go
@@ -48,3 +48,13 @@ func getFdLimit() (int, error) {
}
return int(limit.Cur), nil
}
+
+// getFdMaxLimit retrieves the maximum number of file descriptors this process is
+// allowed to request for itself.
+func getFdMaxLimit() (int, error) {
+ var limit syscall.Rlimit
+ if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
+ return 0, err
+ }
+ return int(limit.Max), nil
+}
diff --git a/cmd/utils/fdlimit_windows.go b/cmd/utils/fdlimit_windows.go
index 53aad3d7a..f239683d2 100644
--- a/cmd/utils/fdlimit_windows.go
+++ b/cmd/utils/fdlimit_windows.go
@@ -39,3 +39,9 @@ func getFdLimit() (int, error) {
// Please see raiseFdLimit for the reason why we use hard coded 16K as the limit
return 16384, nil
}
+
+// getFdMaxLimit retrieves the maximum number of file descriptors this process is
+// allowed to request for itself.
+func getFdMaxLimit() (int, error) {
+ return getFdLimit()
+}