├── .gitignore ├── macOS ├── welcome.txt ├── entitlements.plist └── Distribution.xml ├── SECURITY.md ├── tests └── goss.yaml ├── go.mod ├── Dockerfile ├── .github └── workflows │ ├── publish.yml │ ├── release.yml │ └── go.yml ├── go.sum ├── README.md ├── NOTICE.txt ├── Makefile ├── LICENSE.txt ├── release-notes.txt └── fmcsadmin_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.out 2 | .glide/ 3 | .DS_Store 4 | bin 5 | dist 6 | -------------------------------------------------------------------------------- /macOS/welcome.txt: -------------------------------------------------------------------------------- 1 | fmcsadmin is the command line tool to administer the Database Server component of Claris FileMaker Server via Claris FileMaker Admin API. -------------------------------------------------------------------------------- /macOS/entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.network.client 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | The latest minor version of fmcsadmin 2 is supported. 6 | 7 | | Version | Supported | 8 | | ------- | - | 9 | | 2.3.x | ✅ | 10 | | < 2.3 | ❌ | 11 | 12 | ## Reporting a Vulnerability 13 | 14 | Please open an issue or contact the main author directly (famlog at gmail). 15 | -------------------------------------------------------------------------------- /tests/goss.yaml: -------------------------------------------------------------------------------- 1 | command: 2 | {{if .Env.OS | regexMatch "(darwin|linux)"}} 3 | print-version: 4 | exec: "./fmcsadmin -v" 5 | exit-status: 0 6 | stdout: 7 | - "2.3.0" 8 | {{end}} 9 | 10 | {{if eq .Env.OS "windows"}} 11 | print-version: 12 | exec: "fmcsadmin.exe -v" 13 | exit-status: 0 14 | stdout: "fmcsadmin 2.3.0\n" 15 | {{end}} 16 | 17 | {{if eq .Env.OS "darwin"}} 18 | check-universal-binary-or-not: 19 | exec: "file ./fmcsadmin" 20 | exit-status: 0 21 | stdout: 22 | - "Mach-O 64-bit executable x86_64" 23 | - "Mach-O 64-bit executable arm64" 24 | {{end}} 25 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/emic/fmcsadmin 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.7 6 | 7 | require ( 8 | github.com/golang-jwt/jwt/v5 v5.2.1 9 | github.com/mattn/go-scan v0.0.0-20200228002420-2250e6e52487 10 | github.com/olekukonko/tablewriter v0.0.5 11 | github.com/stretchr/testify v1.10.0 12 | golang.org/x/term v0.30.0 13 | ) 14 | 15 | require ( 16 | github.com/davecgh/go-spew v1.1.1 // indirect 17 | github.com/mattn/go-runewidth v0.0.16 // indirect 18 | github.com/pmezard/go-difflib v1.0.0 // indirect 19 | github.com/rivo/uniseg v0.4.7 // indirect 20 | golang.org/x/sys v0.31.0 // indirect 21 | gopkg.in/yaml.v3 v3.0.1 // indirect 22 | ) 23 | -------------------------------------------------------------------------------- /macOS/Distribution.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | fmcsadmin 2.3.0 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | fmcsadmin.pkg 18 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM --platform=linux/x86_64 ubuntu:24.04 2 | 3 | RUN apt update && apt install -y curl tar make bash git build-essential 4 | 5 | # Install Go 6 | WORKDIR /root 7 | 8 | RUN curl -LO https://go.dev/dl/go1.22.10.linux-amd64.tar.gz && tar -C /tmp -xzf go1.22.10.linux-amd64.tar.gz && rm -f /root/go1.22.10.linux-amd64.tar.gz && mv /tmp/go go1.22 9 | 10 | WORKDIR /root/go/src/go.googlesource.com/go 11 | 12 | RUN git clone https://go.googlesource.com/go goroot && cd goroot && git checkout release-branch.go1.23 && cd src && export GOROOT_BOOTSTRAP=/root/go1.22 && ./all.bash 13 | 14 | RUN cp -pr /root/go/src/go.googlesource.com/go/goroot /usr/local/go 15 | 16 | RUN /usr/local/go/bin/go version 17 | 18 | # Install Goss 19 | WORKDIR /root/go/src/github.com/goss-org 20 | 21 | ARG GOSS_VERSION="0.4.9" 22 | ARG GOSS_COMMIT_HASH="5704120d25902119cb1139e04bca3db7742a9f73" 23 | 24 | RUN curl -L https://github.com/goss-org/goss/archive/${GOSS_COMMIT_HASH}.tar.gz | tar -xzvf - 25 | 26 | RUN mv goss-${GOSS_COMMIT_HASH} goss && cd goss && PATH=$PATH:/usr/local/go/bin TRAVIS_TAG=${GOSS_VERSION} make build 27 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Image 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'Dockerfile' 7 | 8 | jobs: 9 | publish: 10 | name: Publish Image 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v4 15 | - name: Set up QEMU 16 | uses: docker/setup-qemu-action@v3 17 | - name: Set up Docker Buildx 18 | uses: docker/setup-buildx-action@v3 19 | - name: Login to GitHub Container Registry 20 | uses: docker/login-action@v3 21 | with: 22 | registry: ghcr.io 23 | username: ${{ github.actor }} 24 | password: ${{ secrets.GHCR_TOKEN_202507 }} 25 | - name: Container meta 26 | id: meta 27 | uses: docker/metadata-action@v5 28 | with: 29 | images: ghcr.io/matsuo/goss 30 | tags: | 31 | type=raw,value=latest 32 | type=sha,prefix=,suffix=,format=short 33 | - name: Push to GitHub Container Registry 34 | uses: docker/build-push-action@v6 35 | with: 36 | context: . 37 | push: true 38 | tags: ${{ steps.meta.outputs.tags }} 39 | labels: ${{ steps.meta.outputs.labels }} 40 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= 4 | github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= 5 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 6 | github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= 7 | github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 8 | github.com/mattn/go-scan v0.0.0-20200228002420-2250e6e52487 h1:FsO95DVHMp/Eldk9cjfPdO+aCM8csjrsMX6daS0xFuE= 9 | github.com/mattn/go-scan v0.0.0-20200228002420-2250e6e52487/go.mod h1:sNJr+MyYo/WAx30FGeqHkJGtNyqmD6oQyfHrwC/tDVo= 10 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 11 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 12 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 13 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 14 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 15 | github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 16 | github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 17 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 18 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 19 | golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= 20 | golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 21 | golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= 22 | golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= 23 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 24 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 25 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 26 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | fmcsadmin [![Build Status](https://github.com/emic/fmcsadmin/actions/workflows/go.yml/badge.svg)](https://github.com/emic/fmcsadmin/actions/workflows/go.yml) 2 | ========= 3 | fmcsadmin is a command line tool to administer the Database Server component of Claris FileMaker Server via Claris FileMaker Admin API. fmcsadmin supports public key authentication and remote server administration. 4 | 5 | Features 6 | ----- 7 | - Close databases 8 | - Delete a schedule 9 | - Disable schedules 10 | - Disconnect clients 11 | - Enable schedules 12 | - List clients, databases or schedules 13 | - Open databases 14 | - Temporarily stop database access 15 | - Make paused databases available 16 | - Run a schedule 17 | - Send a message to clients 18 | - Start a server process 19 | - Restart a server process 20 | - Stop a server process 21 | - Retrieve server or CWP configuration settings 22 | - Change server or CWP configuration settings 23 | - List plug-ins 24 | - Manage SSL certificates 25 | - Move databases out of hosted folder 26 | - View and change the setting for sharing streaming URLs 27 | - Cancel the currently running backup 28 | - View and change the setting for parallel backup 29 | - FileMaker Admin API PKI Authentication 30 | - View and change the settings for the persistent cache (for FileMaker Server 2024) 31 | - View and change the setting for blocking new users (for FileMaker Server 2024) 32 | - View and change the HTTPS tunneling setting for FileMaker Pro and FileMaker Go (for FileMaker Server 2024 (21.1)) 33 | - View and change the "Only open last opened databases" setting (for FileMaker Server 2024 (21.1)) 34 | 35 | Supported Servers 36 | ----- 37 | Please see details: https://support.claris.com/s/article/Claris-support-policy?language=en_US 38 | - Claris FileMaker Server 2024 (until June 2026) 39 | - Claris FileMaker Server 2023 (until Apr 2025) 40 | 41 | Usage 42 | ----- 43 | You can script many tasks with fmcsadmin by using a scripting language that allows execution of shell or terminal commands. 44 | 45 | ``` 46 | fmcsadmin HELP COMMANDS 47 | Lists available commands 48 | 49 | fmcsadmin HELP [COMMAND] 50 | Displays help on the specified COMMAND 51 | 52 | fmcsadmin HELP OPTIONS 53 | Lists available options 54 | ``` 55 | Note: Handling schedule ID 1 is not supported for FileMaker Server. 56 | 57 | Noteworthy Options 58 | ----- 59 | - --fqdn (for remote server administration) 60 | - -i (for PKI authentication) 61 | 62 | ``` 63 | fmcsadmin --fqdn fms.example.com -i /path/to/IDENTITYFILE list files 64 | ``` 65 | 66 | System Requirements 67 | ----- 68 | - Linux version : Ubuntu 20.04 LTS, Ubuntu 22.04 LTS or Ubuntu 22.04 LTS for ARM 69 | - macOS version : macOS Ventura 13, macOS Sonoma 14 or macOS Sequoia 15 70 | - Windows version : Windows Server 2019, Windows Server 2022, Windows 10 Version 22H2, Windows 11 Version 22H2 or later 71 | 72 | Download 73 | ----- 74 | Download from the [latest release page](https://github.com/emic/fmcsadmin/releases/latest). 75 | 76 | Author 77 | ----- 78 | Emic Corporation 79 | 80 | License 81 | ----- 82 | This software is distributed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0), see LICENSE.txt and NOTICE.txt for more information. 83 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | build: 10 | name: Release 11 | runs-on: ${{ matrix.os }} 12 | 13 | strategy: 14 | matrix: 15 | # https://docs.github.com/ja/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners 16 | os: [ 'macos-latest' ] 17 | steps: 18 | 19 | - uses: actions/checkout@v4 20 | 21 | - name: Setup go 22 | uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 23 | with: 24 | cache: false 25 | go-version-file: 'go.mod' 26 | check-latest: true 27 | 28 | - run: make dist 29 | 30 | 31 | - name: Set version 32 | id: version 33 | run: | 34 | VERSION=$(echo ${{ github.ref }} | sed -e "s#refs/tags/##g") 35 | echo ::set-output name=version::$VERSION 36 | 37 | - name: Create release 38 | id: create_release 39 | uses: actions/create-release@0cb9c9b65d5d1901c1f53e5e66eaf4afd303e70e # v1.1.4 40 | if: startsWith(github.ref, 'refs/tags/') 41 | env: 42 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 43 | with: 44 | tag_name: ${{ steps.version.outputs.version }} 45 | release_name: fmcadmin ${{ steps.version.outputs.version }} Released 46 | draft: true 47 | prerelease: false 48 | 49 | - name: Upload Release Asset for Linux (amd64) 50 | id: upload-release-asset-for-linux 51 | uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 # v1.0.2 52 | if: startsWith(github.ref, 'refs/tags/') 53 | env: 54 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 55 | with: 56 | upload_url: ${{ steps.create_release.outputs.upload_url }} 57 | asset_path: ./dist/fmcsadmin-${{ steps.version.outputs.version }}-linux.tar.gz 58 | asset_name: fmcsadmin-${{ steps.version.outputs.version }}-linux.tar.gz 59 | asset_content_type: application/gzip 60 | 61 | - name: Upload Release Asset for Linux (arm64) 62 | id: upload-release-asset-for-linux-arm64 63 | uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 # v1.0.2 64 | if: startsWith(github.ref, 'refs/tags/') 65 | env: 66 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 67 | with: 68 | upload_url: ${{ steps.create_release.outputs.upload_url }} 69 | asset_path: ./dist/fmcsadmin-${{ steps.version.outputs.version }}-linux-arm64.tar.gz 70 | asset_name: fmcsadmin-${{ steps.version.outputs.version }}-linux-arm64.tar.gz 71 | asset_content_type: application/gzip 72 | 73 | - name: Upload Release Asset for Windows (x64) 74 | id: upload-release-asset-for-windows-x64 75 | uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 # v1.0.2 76 | if: startsWith(github.ref, 'refs/tags/') 77 | env: 78 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 79 | with: 80 | upload_url: ${{ steps.create_release.outputs.upload_url }} 81 | asset_path: ./dist/fmcsadmin-${{ steps.version.outputs.version }}-windows-x64.zip 82 | asset_name: fmcsadmin-${{ steps.version.outputs.version }}-windows-x64.zip 83 | asset_content_type: application/zip 84 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | fmcsadmin 2 | Copyright 2017-2025 Emic Corporation, https://www.emic.co.jp/ 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | --- 17 | 18 | go-scan 19 | Copyright © 2013-2020 Yasuhiro Matsumoto, http://mattn.kaoriya.net 20 | 21 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 22 | 23 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | --- 28 | 29 | ASCII Table Writer 30 | Copyright (C) 2014 by Oleku Konko 31 | 32 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 33 | 34 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 35 | 36 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 37 | 38 | --- 39 | 40 | Copyright (c) 2012 Dave Grijalva 41 | Copyright (c) 2021 golang-jwt maintainers 42 | 43 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 44 | 45 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 46 | 47 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 48 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | NAME=fmcsadmin 2 | VERSION=2.3.0 3 | 4 | GOCMD=go 5 | GOBUILD=$(GOCMD) build 6 | GOTEST=$(GOCMD) test 7 | GOGET=$(GOCMD) get 8 | GOINSTALL=$(GOCMD) install 9 | DIST_DIR=dist 10 | LINUX_DIR=linux 11 | LINUX_ARM64_DIR=linux-arm64 12 | MACOS_DIR=macos 13 | MACOS_ALT_DIR=macos-alt 14 | WINDOWS_DIR=windows-x64 15 | DIST_LINUX_DIR=$(NAME)-$(VERSION)-$(LINUX_DIR) 16 | DIST_LINUX_ARM64_DIR=$(NAME)-$(VERSION)-$(LINUX_ARM64_DIR) 17 | DIST_MACOS_DIR=$(NAME)-$(VERSION)-$(MACOS_DIR) 18 | DIST_WINDOWS_DIR=$(NAME)-$(VERSION)-$(WINDOWS_DIR) 19 | 20 | all: test build 21 | 22 | deps: 23 | $(GOGET) github.com/golang-jwt/jwt/v5 24 | $(GOINSTALL) github.com/mattn/go-scan 25 | $(GOINSTALL) github.com/olekukonko/tablewriter 26 | $(GOINSTALL) golang.org/x/term 27 | $(GOINSTALL) github.com/stretchr/testify/assert 28 | 29 | test: deps 30 | $(GOTEST) --cover 31 | 32 | .PHONY: clean 33 | clean: 34 | @rm -rf $(DIST_DIR) 35 | 36 | build: build-linux build-linux-arm64 build-macos build-windows 37 | 38 | build-linux: 39 | mkdir -p $(DIST_DIR)/$(LINUX_DIR) 40 | GOOS=linux GOARCH=amd64 CGO_ENABLED=0 $(GOBUILD) -ldflags "-X main.version=$(VERSION)" -o $(DIST_DIR)/$(LINUX_DIR)/$(NAME) 41 | 42 | build-linux-arm64: 43 | mkdir -p $(DIST_DIR)/$(LINUX_ARM64_DIR) 44 | GOOS=linux GOARCH=arm64 CGO_ENABLED=0 $(GOBUILD) -ldflags "-X main.version=$(VERSION)" -o $(DIST_DIR)/$(LINUX_ARM64_DIR)/$(NAME) 45 | 46 | ifeq ($(shell uname -m),x86_64) 47 | build-macos: 48 | mkdir -p $(DIST_DIR)/$(MACOS_DIR) 49 | GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 $(GOBUILD) -ldflags "-X main.version=$(VERSION)" -o $(DIST_DIR)/$(MACOS_DIR)/$(NAME) 50 | else 51 | build-macos: 52 | mkdir -p $(DIST_DIR)/$(MACOS_DIR) 53 | GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 $(GOBUILD) -ldflags "-X main.version=$(VERSION)" -o $(DIST_DIR)/$(MACOS_DIR)/$(NAME) 54 | endif 55 | 56 | ifeq ($(shell uname -m),x86_64) 57 | build-macos-alt: 58 | mkdir -p $(DIST_DIR)/$(MACOS_ALT_DIR) 59 | GOOS=darwin GOARCH=arm64 CGO_ENABLED=0 $(GOBUILD) -ldflags "-X main.version=$(VERSION)" -o $(DIST_DIR)/$(MACOS_ALT_DIR)/$(NAME) 60 | else 61 | build-macos-alt: 62 | mkdir -p $(DIST_DIR)/$(MACOS_ALT_DIR) 63 | GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 $(GOBUILD) -ldflags "-X main.version=$(VERSION)" -o $(DIST_DIR)/$(MACOS_ALT_DIR)/$(NAME) 64 | endif 65 | 66 | build-windows: 67 | mkdir -p $(DIST_DIR)/$(WINDOWS_DIR) 68 | GOOS=windows GOARCH=amd64 CGO_ENABLED=0 $(GOBUILD) -ldflags "-X main.version=$(VERSION)" -o $(DIST_DIR)/$(WINDOWS_DIR)/$(NAME).exe 69 | 70 | .PHONY: dist 71 | dist-multiplatform: deps build 72 | cd $(DIST_DIR) && \ 73 | mv $(LINUX_DIR) $(DIST_LINUX_DIR) && \ 74 | cp -p ../LICENSE.txt $(DIST_LINUX_DIR)/ && \ 75 | cp -p ../NOTICE.txt $(DIST_LINUX_DIR)/ && \ 76 | cp -p ../README.md $(DIST_LINUX_DIR)/ && \ 77 | cp -p ../release-notes.txt $(DIST_LINUX_DIR)/ && \ 78 | tar -zcf $(DIST_LINUX_DIR).tar.gz $(DIST_LINUX_DIR) && \ 79 | cd .. 80 | 81 | cd $(DIST_DIR) && \ 82 | mv $(LINUX_ARM64_DIR) $(DIST_LINUX_ARM64_DIR) && \ 83 | cp -p ../LICENSE.txt $(DIST_LINUX_ARM64_DIR)/ && \ 84 | cp -p ../NOTICE.txt $(DIST_LINUX_ARM64_DIR)/ && \ 85 | cp -p ../README.md $(DIST_LINUX_ARM64_DIR)/ && \ 86 | cp -p ../release-notes.txt $(DIST_LINUX_ARM64_DIR)/ && \ 87 | tar -zcf $(DIST_LINUX_ARM64_DIR).tar.gz $(DIST_LINUX_ARM64_DIR) && \ 88 | cd .. 89 | 90 | cd $(DIST_DIR) && \ 91 | mv $(MACOS_DIR) $(DIST_MACOS_DIR) && \ 92 | cp -p ../LICENSE.txt $(DIST_MACOS_DIR)/ && \ 93 | cp -p ../NOTICE.txt $(DIST_MACOS_DIR)/ && \ 94 | cp -p ../README.md $(DIST_MACOS_DIR)/ && \ 95 | cp -p ../release-notes.txt $(DIST_MACOS_DIR)/ && \ 96 | cd .. 97 | 98 | cd $(DIST_DIR) && \ 99 | mv $(WINDOWS_DIR) $(DIST_WINDOWS_DIR) && \ 100 | cp -p ../LICENSE.txt $(DIST_WINDOWS_DIR)/ && \ 101 | cp -p ../NOTICE.txt $(DIST_WINDOWS_DIR)/ && \ 102 | cp -p ../README.md $(DIST_WINDOWS_DIR)/ && \ 103 | cp -p ../release-notes.txt $(DIST_WINDOWS_DIR)/ && \ 104 | zip -r $(DIST_WINDOWS_DIR).zip $(DIST_WINDOWS_DIR) && \ 105 | cd .. 106 | 107 | ifeq ($(shell uname),Darwin) 108 | dist: dist-multiplatform build-macos-alt 109 | cd $(DIST_DIR) && \ 110 | mv $(DIST_MACOS_DIR)/$(NAME) $(DIST_MACOS_DIR)/$(NAME).tmp && \ 111 | lipo -create $(DIST_MACOS_DIR)/$(NAME).tmp $(MACOS_ALT_DIR)/$(NAME) -output $(DIST_MACOS_DIR)/$(NAME) && \ 112 | rm -f $(MACOS_ALT_DIR)/$(NAME) && \ 113 | rmdir $(MACOS_ALT_DIR) && \ 114 | rm -f $(DIST_MACOS_DIR)/$(NAME).tmp && \ 115 | cd .. 116 | else 117 | dist: dist-multiplatform 118 | endif -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | 7 | build: 8 | name: Build 9 | runs-on: ${{ matrix.os }} 10 | 11 | strategy: 12 | matrix: 13 | # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners 14 | os: [ 'ubuntu-20.04', 'ubuntu-22.04', 'ubuntu-22.04-arm', 'ubuntu-24.04', 'ubuntu-24.04-arm', 'ubuntu-latest', 'macos-13', 'macos-14', 'macos-15', 'macos-latest', 'windows-2019', 'windows-2022', 'windows-2025', 'windows-latest' ] 15 | steps: 16 | 17 | - uses: actions/checkout@v4 18 | 19 | - name: Setup go 20 | uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0 21 | with: 22 | cache: false 23 | go-version-file: 'go.mod' 24 | check-latest: true 25 | 26 | - run: go test 27 | 28 | - shell: bash 29 | run: cat Makefile | grep "^VERSION=" | sed -e "s/VERSION/fmcsadmin_version/g" >> "$GITHUB_ENV" 30 | 31 | - run: go build -ldflags "-X main.version=${{ env.fmcsadmin_version }}" fmcsadmin.go 32 | 33 | - if: runner.os == 'macOS' 34 | run: make dist && cp -p "dist/fmcsadmin-${{ env.fmcsadmin_version }}-macos/fmcsadmin" . 35 | 36 | - shell: bash 37 | run: echo "goss_commit_hash=5704120d25902119cb1139e04bca3db7742a9f73" >> "$GITHUB_ENV" # v0.4.9 38 | 39 | - if: runner.os == 'macOS' || runner.os == 'Windows' 40 | shell: bash 41 | run: echo "GOSS_USE_ALPHA=1" >> "$GITHUB_ENV" 42 | 43 | - if: runner.os == 'Linux' && (github.repository_owner == 'emic' || github.repository_owner == 'matsuo') 44 | name: Login to GitHub Container Registry 45 | uses: docker/login-action@v3 46 | with: 47 | registry: ghcr.io 48 | username: ${{ github.actor }} 49 | password: ${{ secrets.GHCR_TOKEN_202507 }} 50 | 51 | - if: (matrix.os == 'ubuntu-22.04' || matrix.os == 'ubuntu-24.04' || matrix.os == 'ubuntu-latest') && (github.repository_owner == 'emic' || github.repository_owner == 'matsuo') 52 | name: Pull from GitHub Container Registry 53 | run: | 54 | docker pull ghcr.io/matsuo/goss:latest 55 | docker run --rm -i -v /$(pwd):/tmp ghcr.io/matsuo/goss:latest bash <<'EOF' 56 | cd /root/go/src/github.com/goss-org/goss 57 | cp ./release/goss-darwin-amd64 /tmp/goss-darwin-amd64 58 | cp ./release/goss-darwin-arm64 /tmp/goss-darwin-arm64 59 | cp ./release/goss-linux-amd64 /tmp/goss-linux-amd64 60 | cp ./release/goss-linux-arm64 /tmp/goss-linux-arm64 61 | EOF 62 | 63 | - if: runner.os == 'macOS' || matrix.os == 'ubuntu-22.04-arm' || matrix.os == 'ubuntu-24.04-arm' || (runner.os == 'Linux' && !(github.repository_owner == 'emic' || github.repository_owner == 'matsuo')) 64 | run: | 65 | curl -L "https://github.com/goss-org/goss/archive/${{ env.goss_commit_hash }}.tar.gz" -o goss.tar.gz 66 | tar xzvf goss.tar.gz 67 | cd "goss-${{ env.goss_commit_hash }}" 68 | make build 69 | cd .. 70 | 71 | - if: runner.os == 'Windows' 72 | shell: bash 73 | run: | 74 | curl -L "https://github.com/goss-org/goss/archive/${{ env.goss_commit_hash }}.tar.gz" -o goss.tar.gz 75 | tar xzvf goss.tar.gz 76 | cd "goss-${{ env.goss_commit_hash }}" 77 | go build -o goss-windows-amd64.exe github.com/goss-org/goss/cmd/goss 78 | mkdir release 79 | mv goss-windows-amd64.exe release/ 80 | cd .. 81 | 82 | - if: (matrix.os == 'ubuntu-22.04' || matrix.os == 'ubuntu-24.04' || matrix.os == 'ubuntu-latest') && (github.repository_owner == 'emic' || github.repository_owner == 'matsuo') 83 | run: | 84 | ./goss-linux-amd64 --version 85 | OS=linux ./goss-linux-amd64 --gossfile tests/goss.yaml validate --format documentation 86 | 87 | - if: (matrix.os == 'ubuntu-22.04' || matrix.os == 'ubuntu-24.04' || matrix.os == 'ubuntu-latest') && !(github.repository_owner == 'emic' || github.repository_owner == 'matsuo') 88 | run: | 89 | OS=linux "./goss-${{ env.goss_commit_hash }}/release/goss-linux-amd64" --gossfile tests/goss.yaml validate --format documentation 90 | 91 | - if: matrix.os == 'ubuntu-22.04-arm' || matrix.os == 'ubuntu-24.04-arm' 92 | run: | 93 | OS=linux "./goss-${{ env.goss_commit_hash }}/release/goss-linux-arm64" --gossfile tests/goss.yaml validate --format documentation 94 | 95 | - if: runner.os == 'macOS' 96 | run: | 97 | OS=darwin "./goss-${{ env.goss_commit_hash }}/release/goss-darwin-amd64" --gossfile tests/goss.yaml validate --format documentation 98 | 99 | - if: runner.os == 'Windows' 100 | shell: bash 101 | run: | 102 | OS=windows "./goss-${{ env.goss_commit_hash }}/release/goss-windows-amd64.exe" --gossfile tests/goss.yaml validate --format documentation 103 | 104 | - run: ./fmcsadmin -v 105 | 106 | - name: Create dmg format file for macOS 107 | if: runner.os == 'macOS' 108 | run: | 109 | lipo -info "dist/fmcsadmin-${{ env.fmcsadmin_version }}-macos/fmcsadmin" 110 | cd "dist/fmcsadmin-${{ env.fmcsadmin_version }}-macos" 111 | pkgbuild --root . --identifier jp.co.emic.fmcsadmin --version "${{ env.fmcsadmin_version }}" --install-location /usr/local/bin ../fmcsadmin.pkg 112 | cd .. 113 | cp -p ../{LICENSE.txt,README.md,NOTICE.txt,release-notes.txt} . 114 | cp -p ../macOS/{Distribution.xml,welcome.txt} . 115 | productbuild --distribution Distribution.xml --resources . --package-path fmcsadmin.pkg "fmcsadmin-${{ env.fmcsadmin_version }}-unsigned.pkg" 116 | cp -p "fmcsadmin-${{ env.fmcsadmin_version }}-unsigned.pkg" "fmcsadmin-${{ env.fmcsadmin_version }}.pkg" 117 | mkdir macos-dist 118 | mv "fmcsadmin-${{ env.fmcsadmin_version }}.pkg" macos-dist/ 119 | mv {LICENSE.txt,README.md,NOTICE.txt,release-notes.txt} macos-dist/ 120 | cd macos-dist 121 | cd .. 122 | hdiutil create -srcfolder ./macos-dist/ -fs HFS+ -format UDZO -volname "fmcsadmin-${{ env.fmcsadmin_version }}" "fmcsadmin-${{ env.fmcsadmin_version }}-macos.dmg" 123 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /release-notes.txt: -------------------------------------------------------------------------------- 1 | fmcsadmin 2 | (c) 2017-2025 Emic Corporation 3 | This software is distributed under the Apache License, Version 2.0, see LICENSE.txt and NOTICE.txt for more information. 4 | 5 | Version: 2.3.0 6 | Date: March 6, 2025 7 | - Add support for Claris FileMaker Server 2024 (21.1). 8 | - Add support for macOS Sequoia 15. 9 | - Update "GET SERVERPREFS" command to view the "Only open last opened databases" setting. (Usage: "fmcsadmin get serverprefs OnlyOpenLastOpenedDatabases") 10 | - Update "SET SERVERPREFS" command to open only the databases that were opened when the database server was last shut down. (Usage: "fmcsadmin set serverprefs OnlyOpenLastOpenedDatabases=true") 11 | - Update "GET SERVERPREFS" command to get the https tunneling setting for FileMaker Pro and FileMaker Go. (Usage: "fmcsadmin get serverprefs EnableHttpProtocolNetwork") 12 | - Update "SET SERVERPREFS" command to enable or disable the https tunneling for FileMaker Pro and FileMaker Go. (Usage: "fmcsadmin set serverprefs EnableHttpProtocolNetwork=true") 13 | - Change the error message displayed when executing "get serverprefs" command with invalid arguments on older versions of FileMaker Server. 14 | - Change the error message displayed when executing "set serverprefs" command with invalid arguments on older versions of FileMaker Server. 15 | - Built with Go 1.23. 16 | - [INFO] Drop support for Claris FileMaker Server 19.6. 17 | - [INFO] Drop support for macOS Monterey 12. 18 | - [INFO] Drop support for Windows 11 Version 21H2. 19 | 20 | Version: 2.2.0 21 | Date: August 28, 2024 22 | - Add support for Claris FileMaker Server 2024 (21.0). 23 | - Add support for Claris FileMaker Server 2023 (20.1, 20.2 and 20.3). 24 | - Add support for Ubuntu 22.04 LTS (on amd64 architecture). 25 | - Add support for Ubuntu 22.04 LTS on arm64 architecture. 26 | - Update "GET SERVERPREFS" command to get blocking new users setting for Claris FileMaker Server 2024 (21.0). (Usage: "fmcsadmin get serverprefs BlockNewUsersEnabled") 27 | - Update "SET SERVERPREFS" command to set blocking new users setting for Claris FileMaker Server 2024 (21.0). (Usage: "fmcsadmin set serverprefs BlockNewUsersEnabled=true") 28 | - Update "SET SERVERPREFS" command to set persistent cache setting for Claris FileMaker Server 2024 (21.0). (Usage: "fmcsadmin set serverprefs PersistCacheEnabled=true") 29 | - Update "SET SERVERPREFS" command to set persistent cache sync setting for Claris FileMaker Server 2024 (21.0). To change the value of SyncPersistCache to true, the value of PersistCacheEnabled must be true. (Usage: "fmcsadmin set serverprefs SyncPersistCache=true") 30 | - Update "GET SERVERPREFS" command to get database server auto restart setting for Claris FileMaker Server 2024 (21.0). (Usage: "fmcsadmin get serverprefs DatabaseServerAutoRestart") 31 | - Update "SET SERVERPREFS" command to set database server auto restart setting for Claris FileMaker Server 2024 (21.0). To change the value of DatabaseServerAutoRestart to true, the value of PersistCacheEnabled must be true. (Usage: "fmcsadmin set serverprefs DatabaseServerAutoRestart=true") 32 | - Update "GET SERVERPREFS" command to get persistent cache setting for Claris FileMaker Server 2023 (20.1) or later. (Usage: "fmcsadmin get serverprefs PersistCacheEnabled" or "fmcsadmin get serverprefs SyncPersistCache") 33 | - Update "GET SERVERPREFS" command to get persistent cache sync setting for Claris FileMaker Server 2023 (20.1) or later. (Usage: "fmcsadmin get serverprefs SyncPersistCache") 34 | - Update "GET SERVERCONFIG" command and "GET SERVERPREFS" command due to increasing the maximum number of hosted database files per FileMaker Server instance for Claris FileMaker Server 2023 or later. 35 | - Update "SET SERVERCONFIG" command and "SET SERVERPREFS" command due to increasing the maximum number of hosted database files per FileMaker Server instance for Claris FileMaker Server 2023 or later. 36 | - Modify behavior of outputting error messages for invalid parameters when using "GET SERVERPREFS" and "SET SERVERPREFS" command. 37 | - Add support for Windows Server 2019 and Windows Server 2022. 38 | - Tested with Claris FileMaker Server 2024 (21.0). 39 | - Tested on macOS Sonoma 14. 40 | - Built with Go 1.22. 41 | - [INFO] Drop support for Claris FileMaker Server 19.3, 19.4 and 19.5. 42 | - [INFO] Drop support for Ubuntu 18.04 LTS. 43 | - [INFO] Drop support for CentOS Linux 7. 44 | - [INFO] Drop support for Windows 10 Version 21H2. 45 | - [INFO] Drop support for macOS Big Sur 11. 46 | - [BUG FIX] Fix "SET SERVERPREFS" command was not executed correctly in some cases. 47 | 48 | Version: 2.1.0 49 | Date: May 17, 2023 50 | - Add "-i" option to specify a private key file for FileMaker Admin API PKI Authentication (requires Claris FileMaker Server 19.6.1 or later). 51 | - Update behavior of "GET CWPCONFIG" command and "SET CWPCONFIG" command on Linux for FileMaker Server 19.6.1 or later. 52 | - Detect an invalid configuration value when using "SET CWPCONFIG" command. 53 | - Tested with Claris FileMaker Server 19.6. 54 | - Tested on macOS Ventura 13. 55 | - Fix spelling in help messages. 56 | - Built with Go 1.19. 57 | - [INFO] Drop support for Claris FileMaker Server 19.0, 19.1 and 19.2. 58 | - [INFO] Drop support for macOS Catalina 10.15. 59 | - [INFO] Drop support for Windows 10 Version 21H1. 60 | - [BUG FIX] Fix causing unintended changes of the configuration settings for unspecified options in some cases when using "SET CWPCONFIG" command. 61 | 62 | Version: 2.0.0 63 | Date: June 27, 2022 64 | - Change to the Apache License, Version 2.0. 65 | - Support Ubuntu 20.04 LTS. 66 | - Add "CANCEL" command to cancel the currently running backup for Claris FileMaker Server 19.5.1. (Usage: "fmcsadmin cancel backup") 67 | - Update "GET SERVERPREFS" command to check the status of parallel backup for Claris FileMaker Server 19.5.1. (Usage: "fmcsadmin get serverprefs ParallelBackupEnabled") 68 | - Update "SET SERVERPREFS" command to enable or disable parallel backup for Claris FileMaker Server 19.5.1. (Usage: "fmcsadmin set serverprefs ParallelBackupEnabled=false") 69 | - Add support for credentials via environment variables (FMS_USERNAME and FMS_PASSWORD). 70 | - Add error messages for the FileMaker error code 956, 1702. 71 | - Change an error message when specifying the host name of Claris FileMaker Cloud with "--fqdn" option. 72 | - Tested with Claris FileMaker Server 19.5. 73 | - Tested on Windows 11 and macOS Monterey 12. 74 | - Built with Go 1.18. 75 | - [INFO] Drop support for Claris FileMaker Server 18 and FileMaker Cloud for AWS 1.18. 76 | - [INFO] Drop support for 32-bit Windows version. 77 | - [INFO] Drop support for Windows 10 Version 1903, 1909, 2004 and 20H2. 78 | - [INFO] Drop support for macOS Mojave 10.14. 79 | - [INFO] Drop support for CentOS Linux 8. 80 | - [BUG FIX] Improve DNS error handling when using "--fqdn" option. 81 | - [BUG FIX] Output an error message when using "SET SERVERPREFS" command to set streaming URL cookie check setting with unsupported versions of FileMaker Server. The affected version is 1.3.0 only. 82 | 83 | Version: 1.3.0 84 | Date: August 17, 2021 85 | - Support Ubuntu 18.04 LTS. 86 | - Support Apple Silicon on macOS. 87 | - Add "REMOVE" command to move databases out of hosted folder for Claris FileMaker Server 19.3.1. 88 | - Update "GET SERVERPREFS" command to get streaming URL cookie check setting for Claris FileMaker Server 19.3.2. (Usage: "fmcsadmin get serverprefs AuthenticatedStream") 89 | - Update "SET SERVERPREFS" command to set streaming URL cookie check setting for Claris FileMaker Server 19.3.2. (Usage: "fmcsadmin set serverprefs AuthenticatedStream=1") 90 | - Return the FileMaker error code 10502 when using "LIST" command and fmserverd is stopping. 91 | - Improve error handling in case of detecting server-side error. 92 | - Suppress outputting error messages for debugging. 93 | - Add error messages for the FileMaker error code 1713, 20501. 94 | - Built with Go 1.16. 95 | - [BUG FIX] Detect upper case when using "SET SERVERCONFIG SecureFilesOnly", "SET SERVERPREFS RequireSecureDB" and "SET CWPCONFIG" command. 96 | 97 | Version: 1.2.0 98 | Date: February 17, 2021 99 | - Support Claris FileMaker Server for Linux. 100 | - Add "DELETE" command to delete a schedule. 101 | - Support "PLUGINS" type of "LIST" command to list Database Server calculation plug-ins for Claris FileMaker Server 19.2.1. 102 | - Add "CERTIFICATE" command to manage SSL certificates for Claris FileMaker Server 19.2.1. 103 | - Modify behavior of "GET CWPCONFIG" command and "SET CWPCONFIG" command on Linux. 104 | - Modify behavior of outputting error messages for invalid parameters when using "GET CWPCONFIG", "GET SERVERCONFIG", "SET CWPCONFIG" and "SET SERVERCONFIG" command. 105 | - Modify behavior of outputting error messages for unavailable commands when using "GET SERVERPREFS" command and "SET SERVERPREFS" command. 106 | - Change error code for unavailable commands when using "GET SERVERPREFS" command and "SET SERVERPREFS" command. 107 | - Modify behavior of "DISABLE" command without "-y" or "--yes" option. 108 | - Add error messages for the FileMaker error code 21, 20402, 20405, 20406, 20408, 20630 and 20632. 109 | - Update error messages for the FileMaker error code -1 and 1708. 110 | - Built with Go 1.15. 111 | - [INFO] Drop support for macOS High Sierra 10.13. 112 | - [BUG FIX] Fix compatibility with Claris FileMaker Server 19.1.2 or later when using "SET SERVERCONFIG" command and "SET SERVERPREFS" command. 113 | 114 | Version: 1.1.0 115 | Date: June 17, 2020 116 | - Support "--savekey" option of "OPEN" command for FileMaker Server 19. 117 | - Add the notarized installer for macOS to support macOS Catalina 10.15. 118 | - Built with Go 1.14. 119 | 120 | Version: 1.0.0 121 | Date: September 26, 2019 122 | - Support and require FileMaker Admin API v2 of FileMaker Server 18 and FileMaker Cloud for AWS 1.18. Released as a stable version. 123 | - Change to the MIT License. 124 | - Enable "--fqdn" option for FileMaker Server. 125 | - Add "-f" and "--force" option for forcing database to close or database server to stop, immediately disconnecting clients. 126 | - Add "GET BACKUPTIME" command to retrieve the start time of a specified backup schedule or the start times of all backup schedules for FileMaker Server (Handling schedule ID 1 is not supported). 127 | - Add "GET SERVERPREFS" command for FileMaker Server. 128 | - Add "SET SERVERPREFS" command for FileMaker Server. 129 | - Add 32-bit version for Windows. 130 | - [BUG FIX] Modify outputting enabled extended privileges of closed files when using "-s" option of "LIST FILES" command. 131 | 132 | Version: 0.9.3 (beta) 133 | Date: January 28, 2019 134 | - Add an error message for the FileMaker error code 214. 135 | - Built with Go 1.11. 136 | - [BUG FIX] Fix "-m" and "--message" option of "CLOSE" command. The affected version is 0.9.2 only. 137 | - [BUG FIX] Output "File Closed:" when using "-m" or "--message" option of "CLOSE" command and there is no client connected to the specified databases. 138 | 139 | Version: 0.9.2 (beta) 140 | Date: July 6, 2018 141 | - Support FileMaker Admin API (Trial) of FileMaker Server 17 experimentally ("--fqdn" option and handling schedule ID 1 is not supported for FileMaker Server). 142 | - Add "START" command to start a server process for FileMaker Server 17. 143 | - Add "STOP" command to stop a server process for FileMaker Server 17. 144 | - Add "RESTART" command to restart a server process for FileMaker Server 17. 145 | - Add "GET" command to retrieve server or CWP (Custom Web Publishing) configuration settings for FileMaker Server 17. 146 | - Add "SET" command to change server or CWP (Custom Web Publishing) configuration settings for FileMaker Server 17. 147 | - Consider local time zone when listing schedules and outputting timestamp. 148 | - Improve connection error handling. 149 | - Output an error message when detecting an invalid option. 150 | - Add error messages for the FileMaker error code -1, 3 and 4. 151 | - Add error messages for the error code 10001, 10007, 10502, 11000 and 11002. 152 | - Change an error message for the FileMaker error code 9. 153 | - Show an error message of the error code 11005 when specified client ID doesn't exist and using "DISCONNECT" command. 154 | - Adjust showing value of "CONNECT TIME" and "FILE NAME" when listing clients with "STATUS" command. 155 | - Built with Go 1.10. 156 | - [BUG FIX] Fix "DISCONNECT" command. 157 | - [BUG FIX] Show an error message when specified schedule ID doesn't exist and using "ENABLE", "DISABLE" and "RUN" commands. 158 | - [BUG FIX] Fix "SEND" command to send a text message to the clients connected to the specified databases. 159 | - [BUG FIX] Fix showing values of "LAST COMPLETED" and "STATUS" correctly in some cases when listing schedules with "LIST" command. 160 | - [BUG FIX] Fix "STATUS" command to show the status of a specified client number correctly. 161 | - [BUG FIX] Fix "STATUS" command not to show the list of databases when a specified database is not exist. 162 | 163 | Version: 0.9.1 (beta) 164 | Date: February 15, 2018 165 | - Add error messages for the FileMaker error code 10006 and 10908. 166 | - Add NOTICE.txt to the distribution file. 167 | - [BUG FIX] Fix logging out process. 168 | 169 | Version: 0.9.0 (beta) 170 | Date: December 22, 2017 171 | - Initial release supporting FileMaker Admin API (Trial). Released as a beta version under the Apache License, Version 2.0. 172 | -------------------------------------------------------------------------------- /fmcsadmin_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "log" 8 | "net" 9 | "net/http" 10 | "net/http/httptest" 11 | "runtime" 12 | "strings" 13 | "testing" 14 | "time" 15 | 16 | "github.com/stretchr/testify/assert" 17 | ) 18 | 19 | func TestRun(t *testing.T) { 20 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 21 | cli := &cli{outStream: outStream, errStream: errStream} 22 | var args []string 23 | var status int 24 | 25 | args = strings.Split("fmcsadmin", " ") 26 | status = cli.Run(args) 27 | assert.Equal(t, 0, status) 28 | 29 | args = strings.Split("fmcsadmin -V", " ") 30 | status = cli.Run(args) 31 | assert.Equal(t, 248, status) 32 | 33 | args = strings.Split("fmcsadmin certificate", " ") 34 | status = cli.Run(args) 35 | assert.Equal(t, 248, status) 36 | 37 | args = strings.Split("fmcsadmin close -b", " ") 38 | status = cli.Run(args) 39 | assert.Equal(t, 249, status) 40 | 41 | args = strings.Split("fmcsadmin close --unknown", " ") 42 | status = cli.Run(args) 43 | assert.Equal(t, 249, status) 44 | 45 | args = strings.Split("fmcsadmin disconnect unknown", " ") 46 | status = cli.Run(args) 47 | assert.Equal(t, 248, status) 48 | 49 | args = strings.Split("fmcsadmin disconnect 0", " ") 50 | status = cli.Run(args) 51 | assert.Equal(t, 248, status) 52 | 53 | args = strings.Split("fmcsadmin list", " ") 54 | status = cli.Run(args) 55 | assert.Equal(t, 248, status) 56 | 57 | args = strings.Split("fmcsadmin list unknown", " ") 58 | status = cli.Run(args) 59 | assert.Equal(t, 248, status) 60 | 61 | args = strings.Split("fmcsadmin get", " ") 62 | status = cli.Run(args) 63 | assert.Equal(t, 248, status) 64 | 65 | args = strings.Split("fmcsadmin get cwpconfig invalidparameter", " ") 66 | status = cli.Run(args) 67 | assert.Equal(t, 10001, status) 68 | 69 | args = strings.Split("fmcsadmin get cwpconfig invalidparameter", " ") 70 | _ = cli.Run(args) 71 | expected := "Invalid configuration name: invalidparameter" 72 | assert.Contains(t, outStream.String(), expected) 73 | 74 | args = strings.Split("fmcsadmin get serverconfig invalidparameter", " ") 75 | status = cli.Run(args) 76 | assert.Equal(t, 10001, status) 77 | 78 | args = strings.Split("fmcsadmin get serverprefs invalidparameter", " ") 79 | status = cli.Run(args) 80 | assert.Equal(t, 10001, status) 81 | 82 | args = strings.Split("fmcsadmin get unknown", " ") 83 | status = cli.Run(args) 84 | assert.Equal(t, 248, status) 85 | 86 | args = strings.Split("fmcsadmin restart", " ") 87 | status = cli.Run(args) 88 | if runtime.GOOS == "darwin" || runtime.GOOS == "windows" { 89 | assert.Equal(t, 248, status) 90 | } else { 91 | assert.Equal(t, 248, status) 92 | } 93 | 94 | args = strings.Split("fmcsadmin restart unknown -y", " ") 95 | status = cli.Run(args) 96 | if runtime.GOOS == "darwin" || runtime.GOOS == "windows" { 97 | assert.Equal(t, 23, status) 98 | } else { 99 | assert.Equal(t, 23, status) 100 | } 101 | 102 | args = strings.Split("fmcsadmin run unknown", " ") 103 | status = cli.Run(args) 104 | assert.Equal(t, 248, status) 105 | 106 | args = strings.Split("fmcsadmin set", " ") 107 | status = cli.Run(args) 108 | assert.Equal(t, 248, status) 109 | 110 | args = strings.Split("fmcsadmin set cwpconfig", " ") 111 | status = cli.Run(args) 112 | assert.Equal(t, 10001, status) 113 | 114 | args = strings.Split("fmcsadmin set cwpconfig enablephp", " ") 115 | status = cli.Run(args) 116 | assert.Equal(t, 10001, status) 117 | 118 | args = strings.Split("fmcsadmin set cwpconfig invalidparameter=true", " ") 119 | status = cli.Run(args) 120 | assert.Equal(t, 10001, status) 121 | 122 | args = strings.Split("fmcsadmin set cwpconfig invalidparameter=true", " ") 123 | _ = cli.Run(args) 124 | expected = "Invalid configuration name: invalidparameter" 125 | assert.Contains(t, outStream.String(), expected) 126 | 127 | args = strings.Split("fmcsadmin set serverconfig", " ") 128 | status = cli.Run(args) 129 | assert.Equal(t, 10001, status) 130 | 131 | args = strings.Split("fmcsadmin set serverconfig invalidparameter", " ") 132 | status = cli.Run(args) 133 | assert.Equal(t, 10001, status) 134 | 135 | args = strings.Split("fmcsadmin set serverconfig invalidparameter=true", " ") 136 | status = cli.Run(args) 137 | assert.Equal(t, 10001, status) 138 | 139 | args = strings.Split("fmcsadmin set serverprefs", " ") 140 | status = cli.Run(args) 141 | assert.Equal(t, 10001, status) 142 | 143 | args = strings.Split("fmcsadmin set serverprefs invalidparameter", " ") 144 | status = cli.Run(args) 145 | assert.Equal(t, 10001, status) 146 | 147 | args = strings.Split("fmcsadmin set serverprefs invalidparameter=true", " ") 148 | status = cli.Run(args) 149 | assert.Equal(t, 10001, status) 150 | 151 | args = strings.Split("fmcsadmin set unknown", " ") 152 | status = cli.Run(args) 153 | assert.Equal(t, 248, status) 154 | 155 | args = strings.Split("fmcsadmin start", " ") 156 | status = cli.Run(args) 157 | if runtime.GOOS == "darwin" || runtime.GOOS == "windows" { 158 | assert.Equal(t, 248, status) 159 | } else { 160 | assert.Equal(t, 248, status) 161 | } 162 | 163 | args = strings.Split("fmcsadmin start unknown", " ") 164 | status = cli.Run(args) 165 | if runtime.GOOS == "darwin" || runtime.GOOS == "windows" { 166 | assert.Equal(t, 23, status) 167 | } else { 168 | assert.Equal(t, 23, status) 169 | } 170 | 171 | args = strings.Split("fmcsadmin status unknown", " ") 172 | status = cli.Run(args) 173 | assert.Equal(t, 248, status) 174 | 175 | args = strings.Split("fmcsadmin stop", " ") 176 | status = cli.Run(args) 177 | if runtime.GOOS == "darwin" || runtime.GOOS == "windows" { 178 | assert.Equal(t, 248, status) 179 | } else { 180 | assert.Equal(t, 248, status) 181 | } 182 | 183 | args = strings.Split("fmcsadmin stop unknown -y", " ") 184 | status = cli.Run(args) 185 | if runtime.GOOS == "darwin" || runtime.GOOS == "windows" { 186 | assert.Equal(t, 23, status) 187 | } else { 188 | assert.Equal(t, 23, status) 189 | } 190 | } 191 | 192 | func TestRunInvalidCommand(t *testing.T) { 193 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 194 | cli := &cli{outStream: outStream, errStream: errStream} 195 | 196 | args := strings.Split("fmcsadmin invalidcommand", " ") 197 | status := cli.Run(args) 198 | assert.Equal(t, 248, status) 199 | expected := "Usage: fmcsadmin [options] [COMMAND]" 200 | assert.Contains(t, outStream.String(), expected) 201 | } 202 | 203 | func TestRunWithHelpOption1(t *testing.T) { 204 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 205 | cli := &cli{outStream: outStream, errStream: errStream} 206 | 207 | args := strings.Split("fmcsadmin -h", " ") 208 | status := cli.Run(args) 209 | assert.Equal(t, 0, status) 210 | expected := "Usage: fmcsadmin [options] [COMMAND]" 211 | assert.Contains(t, outStream.String(), expected) 212 | } 213 | 214 | func TestRunWithHelpOption2(t *testing.T) { 215 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 216 | cli := &cli{outStream: outStream, errStream: errStream} 217 | 218 | args := strings.Split("fmcsadmin --help", " ") 219 | status := cli.Run(args) 220 | assert.Equal(t, 0, status) 221 | expected := "Usage: fmcsadmin [options] [COMMAND]" 222 | assert.Contains(t, outStream.String(), expected) 223 | } 224 | 225 | func TestRunWithIdentityFileOption(t *testing.T) { 226 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 227 | cli := &cli{outStream: outStream, errStream: errStream} 228 | 229 | args := strings.Split("fmcsadmin -i notexist.pub list files", " ") 230 | status := cli.Run(args) 231 | assert.Equal(t, 20405, status) 232 | } 233 | 234 | func TestRunWithVersionOption1(t *testing.T) { 235 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 236 | cli := &cli{outStream: outStream, errStream: errStream} 237 | 238 | args := strings.Split("fmcsadmin -v", " ") 239 | status := cli.Run(args) 240 | assert.Equal(t, 0, status) 241 | expected := "fmcsadmin" 242 | assert.Contains(t, outStream.String(), expected) 243 | } 244 | 245 | func TestRunWithVersionOption2(t *testing.T) { 246 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 247 | cli := &cli{outStream: outStream, errStream: errStream} 248 | 249 | args := strings.Split("fmcsadmin --version", " ") 250 | status := cli.Run(args) 251 | assert.Equal(t, 0, status) 252 | expected := "fmcsadmin" 253 | assert.Contains(t, outStream.String(), expected) 254 | } 255 | 256 | func TestRunCancelCommand(t *testing.T) { 257 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 258 | cli := &cli{outStream: outStream, errStream: errStream} 259 | 260 | args := strings.Split("fmcsadmin cancel", " ") 261 | status := cli.Run(args) 262 | assert.Equal(t, 248, status) 263 | expected := "Error: 11000 (Invalid command)" 264 | assert.Contains(t, outStream.String(), expected) 265 | } 266 | 267 | func TestRunDeleteCommand1(t *testing.T) { 268 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 269 | cli := &cli{outStream: outStream, errStream: errStream} 270 | 271 | args := strings.Split("fmcsadmin delete", " ") 272 | status := cli.Run(args) 273 | assert.Equal(t, 248, status) 274 | expected := "Error: 11000 (Invalid command)" 275 | assert.Contains(t, outStream.String(), expected) 276 | } 277 | 278 | func TestRunDeleteCommand2(t *testing.T) { 279 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 280 | cli := &cli{outStream: outStream, errStream: errStream} 281 | 282 | args := strings.Split("fmcsadmin delete schedule", " ") 283 | status := cli.Run(args) 284 | assert.Equal(t, 0, status) 285 | expected := "fmcsadmin: really delete a schedule? (y, n)" 286 | assert.Contains(t, outStream.String(), expected) 287 | } 288 | 289 | func TestRunDisableCommand1(t *testing.T) { 290 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 291 | cli := &cli{outStream: outStream, errStream: errStream} 292 | 293 | args := strings.Split("fmcsadmin disable", " ") 294 | status := cli.Run(args) 295 | assert.Equal(t, 248, status) 296 | expected := "Error: 11000 (Invalid command)" 297 | assert.Contains(t, outStream.String(), expected) 298 | } 299 | 300 | func TestRunDisableCommand2(t *testing.T) { 301 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 302 | cli := &cli{outStream: outStream, errStream: errStream} 303 | 304 | args := strings.Split("fmcsadmin disable schedule", " ") 305 | status := cli.Run(args) 306 | assert.Equal(t, 0, status) 307 | expected := "fmcsadmin: really disable schedule(s)? (y, n) " 308 | assert.Contains(t, outStream.String(), expected) 309 | } 310 | 311 | func TestRunDisableCommand3(t *testing.T) { 312 | running := true 313 | url := "http://127.0.0.1:16001/fmi/admin/api/v2/user/auth" 314 | _, err := http.Get(url) 315 | if err != nil { 316 | running = false 317 | } 318 | 319 | if running == true { 320 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 321 | cli := &cli{outStream: outStream, errStream: errStream} 322 | args := strings.Split("fmcsadmin -u USERNAME -p PASSWORD -y disable schedule", " ") 323 | status := cli.Run(args) 324 | assert.Equal(t, 10600, status) 325 | expected := "Error: 10600 (Schedule at specified index does not exist)" 326 | assert.Contains(t, outStream.String(), expected) 327 | } 328 | } 329 | 330 | func TestRunDisconnectCommand1(t *testing.T) { 331 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 332 | cli := &cli{outStream: outStream, errStream: errStream} 333 | 334 | args := strings.Split("fmcsadmin disconnect", " ") 335 | status := cli.Run(args) 336 | assert.Equal(t, 248, status) 337 | expected := "Error: 11000 (Invalid command)" 338 | assert.Contains(t, outStream.String(), expected) 339 | } 340 | 341 | func TestRunableEnbleCommand1(t *testing.T) { 342 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 343 | cli := &cli{outStream: outStream, errStream: errStream} 344 | 345 | args := strings.Split("fmcsadmin enable", " ") 346 | status := cli.Run(args) 347 | assert.Equal(t, 248, status) 348 | expected := "Error: 11000 (Invalid command)" 349 | assert.Contains(t, outStream.String(), expected) 350 | } 351 | 352 | /* 353 | func TestRunEnableCommand2(t *testing.T) { 354 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 355 | cli := &cli{outStream: outStream, errStream: errStream} 356 | 357 | args := strings.Split("fmcsadmin -y enable schedule", " ") 358 | status := cli.Run(args) 359 | assert.Equal(t, 104, status) 360 | expected := "Error: 10600 (Schedule at specified index does not exist)" 361 | assert.Contains(t, outStream.String(), expected) 362 | } 363 | */ 364 | 365 | func TestRunHelpCommand1(t *testing.T) { 366 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 367 | cli := &cli{outStream: outStream, errStream: errStream} 368 | 369 | args := strings.Split("fmcsadmin help", " ") 370 | status := cli.Run(args) 371 | assert.Equal(t, 0, status) 372 | expected := "Usage: fmcsadmin [options] [COMMAND]" 373 | assert.Contains(t, outStream.String(), expected) 374 | } 375 | 376 | func TestRunHelpCommand2(t *testing.T) { 377 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 378 | cli := &cli{outStream: outStream, errStream: errStream} 379 | 380 | args := strings.Split("fmcsadmin help commands", " ") 381 | status := cli.Run(args) 382 | assert.Equal(t, 0, status) 383 | expected := "fmcsadmin commands are:" 384 | assert.Contains(t, outStream.String(), expected) 385 | } 386 | 387 | func TestRunHelpCommand3(t *testing.T) { 388 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 389 | cli := &cli{outStream: outStream, errStream: errStream} 390 | 391 | args := strings.Split("fmcsadmin help options", " ") 392 | status := cli.Run(args) 393 | assert.Equal(t, 0, status) 394 | expected := "Many fmcsadmin commands take options and parameters." 395 | assert.Contains(t, outStream.String(), expected) 396 | } 397 | 398 | func TestRunHelpCommand4(t *testing.T) { 399 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 400 | cli := &cli{outStream: outStream, errStream: errStream} 401 | 402 | args := strings.Split("fmcsadmin help invalidoption", " ") 403 | status := cli.Run(args) 404 | assert.Equal(t, 0, status) 405 | expected := "Usage: fmcsadmin [options] [COMMAND]" 406 | assert.Contains(t, outStream.String(), expected) 407 | } 408 | 409 | func TestRunRunCommand1(t *testing.T) { 410 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 411 | cli := &cli{outStream: outStream, errStream: errStream} 412 | 413 | args := strings.Split("fmcsadmin run", " ") 414 | status := cli.Run(args) 415 | assert.Equal(t, 248, status) 416 | expected := "Error: 11000 (Invalid command)" 417 | assert.Contains(t, outStream.String(), expected) 418 | } 419 | 420 | /* 421 | func TestRunRunCommand2(t *testing.T) { 422 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 423 | cli := &cli{outStream: outStream, errStream: errStream} 424 | 425 | args := strings.Split("fmcsadmin -y run schedule", " ") 426 | status := cli.Run(args) 427 | assert.Equal(t, 104, status) 428 | expected := "Error: 10600 (Schedule at specified index does not exist)" 429 | assert.Contains(t, outStream.String(), expected) 430 | } 431 | */ 432 | 433 | func TestRunShowCertificateCommandHelp(t *testing.T) { 434 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 435 | cli := &cli{outStream: outStream, errStream: errStream} 436 | 437 | args := strings.Split("fmcsadmin help certificate", " ") 438 | status := cli.Run(args) 439 | assert.Equal(t, 0, status) 440 | expected := "Usage: fmcsadmin CERTIFICATE [CERT_OP] [options] [NAME] [FILE]" 441 | assert.Contains(t, outStream.String(), expected) 442 | } 443 | 444 | func TestRunShowCloseCommandHelp(t *testing.T) { 445 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 446 | cli := &cli{outStream: outStream, errStream: errStream} 447 | 448 | args := strings.Split("fmcsadmin help close", " ") 449 | status := cli.Run(args) 450 | assert.Equal(t, 0, status) 451 | expected := "Usage: fmcsadmin CLOSE [FILE...] [PATH...] [options]" 452 | assert.Contains(t, outStream.String(), expected) 453 | } 454 | 455 | func TestRunShowDeleteCommandHelp(t *testing.T) { 456 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 457 | cli := &cli{outStream: outStream, errStream: errStream} 458 | 459 | args := strings.Split("fmcsadmin help delete", " ") 460 | status := cli.Run(args) 461 | assert.Equal(t, 0, status) 462 | expected := "Usage: fmcsadmin DELETE [TYPE] [SCHEDULE_NUMBER]" 463 | assert.Contains(t, outStream.String(), expected) 464 | } 465 | 466 | func TestRunShowDisableCommandHelp(t *testing.T) { 467 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 468 | cli := &cli{outStream: outStream, errStream: errStream} 469 | 470 | args := strings.Split("fmcsadmin help disable", " ") 471 | status := cli.Run(args) 472 | assert.Equal(t, 0, status) 473 | expected := "Usage: fmcsadmin DISABLE [TYPE] [SCHEDULE_NUMBER]" 474 | assert.Contains(t, outStream.String(), expected) 475 | } 476 | 477 | func TestRunShowDisconnectCommandHelp(t *testing.T) { 478 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 479 | cli := &cli{outStream: outStream, errStream: errStream} 480 | 481 | args := strings.Split("fmcsadmin help disconnect", " ") 482 | status := cli.Run(args) 483 | assert.Equal(t, 0, status) 484 | expected := "Usage: fmcsadmin DISCONNECT CLIENT [CLIENT_NUMBER] [options]" 485 | assert.Contains(t, outStream.String(), expected) 486 | } 487 | 488 | func TestRunShowEnableCommandHelp(t *testing.T) { 489 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 490 | cli := &cli{outStream: outStream, errStream: errStream} 491 | 492 | args := strings.Split("fmcsadmin help enable", " ") 493 | status := cli.Run(args) 494 | assert.Equal(t, 0, status) 495 | expected := "Usage: fmcsadmin ENABLE [TYPE] [SCHEDULE_NUMBER]" 496 | assert.Contains(t, outStream.String(), expected) 497 | } 498 | 499 | func TestRunShowListCommandHelp(t *testing.T) { 500 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 501 | cli := &cli{outStream: outStream, errStream: errStream} 502 | 503 | args := strings.Split("fmcsadmin help list", " ") 504 | status := cli.Run(args) 505 | assert.Equal(t, 0, status) 506 | expected := "Usage: fmcsadmin LIST [TYPE] [options]" 507 | assert.Contains(t, outStream.String(), expected) 508 | } 509 | 510 | func TestRunShowOpenCommandHelp(t *testing.T) { 511 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 512 | cli := &cli{outStream: outStream, errStream: errStream} 513 | 514 | args := strings.Split("fmcsadmin help open", " ") 515 | status := cli.Run(args) 516 | assert.Equal(t, 0, status) 517 | expected := "Usage: fmcsadmin OPEN [options] [FILE...] [PATH...]" 518 | assert.Contains(t, outStream.String(), expected) 519 | } 520 | 521 | func TestRunShowPauseCommandHelp(t *testing.T) { 522 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 523 | cli := &cli{outStream: outStream, errStream: errStream} 524 | 525 | args := strings.Split("fmcsadmin help pause", " ") 526 | status := cli.Run(args) 527 | assert.Equal(t, 0, status) 528 | expected := "Usage: fmcsadmin PAUSE [FILE...] [PATH...]" 529 | assert.Contains(t, outStream.String(), expected) 530 | } 531 | 532 | func TestRunShowRestartCommandHelp(t *testing.T) { 533 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 534 | cli := &cli{outStream: outStream, errStream: errStream} 535 | 536 | args := strings.Split("fmcsadmin help restart", " ") 537 | status := cli.Run(args) 538 | assert.Equal(t, 0, status) 539 | expected := "Usage: fmcsadmin RESTART [TYPE]" 540 | assert.Contains(t, outStream.String(), expected) 541 | } 542 | 543 | func TestRunShowResumeCommandHelp(t *testing.T) { 544 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 545 | cli := &cli{outStream: outStream, errStream: errStream} 546 | 547 | args := strings.Split("fmcsadmin help resume", " ") 548 | status := cli.Run(args) 549 | assert.Equal(t, 0, status) 550 | expected := "Usage: fmcsadmin RESUME [FILE...] [PATH...]" 551 | assert.Contains(t, outStream.String(), expected) 552 | } 553 | 554 | func TestRunShowRunCommandHelp(t *testing.T) { 555 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 556 | cli := &cli{outStream: outStream, errStream: errStream} 557 | 558 | args := strings.Split("fmcsadmin help run", " ") 559 | status := cli.Run(args) 560 | assert.Equal(t, 0, status) 561 | expected := "Usage: fmcsadmin RUN SCHEDULE [SCHEDULE_NUMBER]" 562 | assert.Contains(t, outStream.String(), expected) 563 | } 564 | 565 | func TestRunShowSendCommandHelp(t *testing.T) { 566 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 567 | cli := &cli{outStream: outStream, errStream: errStream} 568 | 569 | args := strings.Split("fmcsadmin help send", " ") 570 | status := cli.Run(args) 571 | assert.Equal(t, 0, status) 572 | expected := "Usage: fmcsadmin SEND [options] [CLIENT_NUMBER] [FILE...] [PATH...]" 573 | assert.Contains(t, outStream.String(), expected) 574 | } 575 | 576 | func TestRunShowStartCommandHelp(t *testing.T) { 577 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 578 | cli := &cli{outStream: outStream, errStream: errStream} 579 | 580 | args := strings.Split("fmcsadmin help start", " ") 581 | status := cli.Run(args) 582 | assert.Equal(t, 0, status) 583 | expected := "Usage: fmcsadmin START [TYPE]" 584 | assert.Contains(t, outStream.String(), expected) 585 | } 586 | 587 | func TestRunShowStatusCommandHelp(t *testing.T) { 588 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 589 | cli := &cli{outStream: outStream, errStream: errStream} 590 | 591 | args := strings.Split("fmcsadmin help status", " ") 592 | status := cli.Run(args) 593 | assert.Equal(t, 0, status) 594 | expected := "Usage: fmcsadmin STATUS [TYPE] [CLIENT_NUMBER] [FILE...]" 595 | assert.Contains(t, outStream.String(), expected) 596 | } 597 | 598 | func TestRunShowStopCommandHelp(t *testing.T) { 599 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 600 | cli := &cli{outStream: outStream, errStream: errStream} 601 | 602 | args := strings.Split("fmcsadmin help stop", " ") 603 | status := cli.Run(args) 604 | assert.Equal(t, 0, status) 605 | expected := "Usage: fmcsadmin STOP [TYPE] [options]" 606 | assert.Contains(t, outStream.String(), expected) 607 | } 608 | 609 | func TestRunCloseCommand1(t *testing.T) { 610 | running := true 611 | url := "http://127.0.0.1:16001/fmi/admin/api/v2/user/auth" 612 | _, err := http.Get(url) 613 | if err != nil { 614 | running = false 615 | } 616 | 617 | if running == false { 618 | handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 619 | fmt.Fprintln(w, "{\"response\": {\"token\": \"ACCESSTOKEN\", \"totalDBCount\": 1, \"clients\": [], \"databases\": [{\"id\": \"1\", \"filename\": \"TestDB.fmp12\", \"status\": \"NORMAL\", \"folder\": \"filemac:/Macintosh HD/Library/FileMaker Server/Data/Databases/Sample/\", \"decryptHint\": \"\"}]}, \"messages\": [{\"code\": \"0\"}]}") 620 | if strings.Contains(r.URL.Path, "/fmi/admin/api/v2/databases/") { 621 | request, _ := io.ReadAll(r.Body) 622 | if strings.Contains(string([]byte(request)), "\"status\":\"CLOSED\"") { 623 | assert.Equal(t, "{\"status\":\"CLOSED\",\"messageText\":\"TESTMESSAGE\",\"force\":false}", string([]byte(request))) 624 | } 625 | } 626 | }) 627 | 628 | address := "127.0.0.1:16001" 629 | l, err := net.Listen("tcp", address) 630 | if err != nil { 631 | log.Fatal(err) 632 | } 633 | ts := httptest.Server{ 634 | Listener: l, 635 | Config: &http.Server{Handler: handler}, 636 | } 637 | ts.Start() 638 | defer ts.Close() 639 | } 640 | 641 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 642 | cli := &cli{outStream: outStream, errStream: errStream} 643 | args := strings.Split("fmcsadmin close TestDB -y -u USERNAME -p PASSWORD -m TESTMESSAGE", " ") 644 | status := cli.Run(args) 645 | assert.Equal(t, 0, status) 646 | expected := "Closing: TestDB.fmp12" 647 | assert.Contains(t, outStream.String(), expected) 648 | } 649 | 650 | func TestRunOpenCommand1(t *testing.T) { 651 | running := true 652 | url := "http://127.0.0.1:16001/fmi/admin/api/v2/user/auth" 653 | _, err := http.Get(url) 654 | if err != nil { 655 | running = false 656 | } 657 | 658 | if running == false { 659 | handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 660 | fmt.Fprintln(w, "{\"response\": {\"token\": \"ACCESSTOKEN\", \"totalDBCount\": 1, \"clients\": [], \"databases\": [{\"id\": \"1\", \"filename\": \"TestDB.fmp12\", \"status\": \"CLOSED\", \"folder\": \"filemac:/Macintosh HD/Library/FileMaker Server/Data/Databases/Sample/\", \"decryptHint\": \"\"}]}, \"messages\": [{\"code\": \"0\"}]}") 661 | if strings.Contains(r.URL.Path, "/fmi/admin/api/v2/databases/") { 662 | request, _ := io.ReadAll(r.Body) 663 | if strings.Contains(string([]byte(request)), "\"status\":\"OPENED\"") { 664 | assert.Equal(t, "{\"status\":\"OPENED\",\"key\":\"\",\"saveKey\":false}", string([]byte(request))) 665 | } 666 | } 667 | }) 668 | 669 | address := "127.0.0.1:16001" 670 | l, err := net.Listen("tcp", address) 671 | if err != nil { 672 | log.Fatal(err) 673 | } 674 | ts := httptest.Server{ 675 | Listener: l, 676 | Config: &http.Server{Handler: handler}, 677 | } 678 | ts.Start() 679 | defer ts.Close() 680 | } 681 | 682 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 683 | cli := &cli{outStream: outStream, errStream: errStream} 684 | args := strings.Split("fmcsadmin open TestDB -u USERNAME -p PASSWORD", " ") 685 | status := cli.Run(args) 686 | assert.Equal(t, 0, status) 687 | expected := "File Opening: TestDB.fmp12" 688 | assert.Contains(t, outStream.String(), expected) 689 | } 690 | func TestRunStatusCommand1(t *testing.T) { 691 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 692 | cli := &cli{outStream: outStream, errStream: errStream} 693 | 694 | args := strings.Split("fmcsadmin status", " ") 695 | status := cli.Run(args) 696 | assert.Equal(t, 248, status) 697 | expected := "Error: 11000 (Invalid command)" 698 | assert.Contains(t, outStream.String(), expected) 699 | } 700 | 701 | func TestGetFlags(t *testing.T) { 702 | var expected []string 703 | var args []string 704 | var resultFlags commandOptions 705 | var cmdArgs []string 706 | 707 | flags := commandOptions{} 708 | flags.helpFlag = false 709 | flags.versionFlag = false 710 | flags.yesFlag = false 711 | flags.statsFlag = false 712 | flags.fqdn = "" 713 | flags.username = "" 714 | flags.password = "" 715 | flags.key = "" 716 | flags.message = "" 717 | flags.clientID = -1 718 | flags.graceTime = 90 719 | 720 | /* 721 | * cancel 722 | * Usage: fmcsadmin CANCEL [TYPE] 723 | * 724 | * fmcsadmin cancel backup 725 | * fmcsadmin cancel -y backup 726 | * fmcsadmin --fqdn example.jp cancel backup 727 | * fmcsadmin --fqdn example.jp cancel -y backup 728 | * fmcsadmin --fqdn example.jp -u USERNAME cancel backup 729 | * fmcsadmin --fqdn example.jp -u USERNAME cancel -y backup 730 | * fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD cancel backup 731 | * fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD cancel -y backup 732 | */ 733 | expected = []string{"cancel", "backup"} 734 | args = strings.Split("fmcsadmin cancel backup", " ") 735 | cmdArgs, resultFlags, _ = getFlags(args, flags) 736 | assert.Equal(t, expected, cmdArgs) 737 | 738 | /* 739 | * certificate 740 | * Usage: fmcsadmin CERTIFICATE [CERT_OP] [options] [NAME] [FILE] 741 | * 742 | * fmcsadmin certificate create "/CN=fms.example.com/C=US" --keyfilepass secret 743 | * fmcsadmin -u USERNAME certificate create "/CN=fms.example.com/C=US" --keyfilepass secret 744 | * fmcsadmin -p PASSWORD certificate create "/CN=fms.example.com/C=US" --keyfilepass secret 745 | * fmcsadmin -u USERNAME -p PASSWORD certificate create "/CN=fms.example.com/C=US" --keyfilepass secret 746 | * fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD certificate create "/CN=fms.example.com/C=US" --keyfilepass secret 747 | * fmcsadmin certificate import --keyfile KEYFILE --keyfilepass secret --intermediateCA intermediateCAfile CRTFILE 748 | * fmcsadmin certificate import --keyfile KEYFILE --keyfilepass secret --intermediateCA intermediateCAfile -y CRTFILE 749 | * fmcsadmin certificate import -u USERNAME --keyfile KEYFILE --keyfilepass secret --intermediateCA intermediateCAfile CRTFILE 750 | * fmcsadmin certificate import -p PASSWORD --keyfile KEYFILE --keyfilepass secret --intermediateCA intermediateCAfile CRTFILE 751 | * fmcsadmin certificate import -u USERNAME -p PASSWORD --keyfile KEYFILE --keyfilepass secret --intermediateCA intermediateCAfile CRTFILE 752 | * fmcsadmin certificate import --fqdn example.jp -u USERNAME -p PASSWORD --keyfile KEYFILE --keyfilepass secret --intermediateCA intermediateCAfile CRTFILE 753 | * fmcsadmin certificate import --fqdn example.jp -u USERNAME -p PASSWORD --keyfile KEYFILE --keyfilepass secret --intermediateCA intermediateCAfile -y CRTFILE 754 | * fmcsadmin certificate delete 755 | * fmcsadmin certificate delete -y 756 | * fmcsadmin -u USERNAME certificate delete 757 | * fmcsadmin -p PASSWORD certificate delete 758 | * fmcsadmin -u USERNAME -p PASSWORD certificate delete 759 | * fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD certificate delete 760 | * fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD certificate delete -y 761 | * etc. 762 | */ 763 | 764 | /* 765 | * close 766 | * Usage: fmcsadmin CLOSE [FILE...] [PATH...] [options] 767 | * 768 | * fmcsadmin close 769 | * fmcsadmin close 1 770 | * fmcsadmin close 1 2 771 | * fmcsadmin close TestDB 772 | * fmcsadmin close TestDB.fmp12 773 | * fmcsadmin close "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB" 774 | * fmcsadmin close "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12" 775 | * fmcsadmin close "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB" 776 | * fmcsadmin close "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12" 777 | * fmcsadmin close "/opt/FileMaker/FileMaker Server/Data/Databases/" 778 | * fmcsadmin close "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/" 779 | * fmcsadmin close TestDB FMServer_Sample 780 | * fmcsadmin --fqdn example.jp close TestDB 781 | * fmcsadmin close -y TestDB 782 | * fmcsadmin close -u USERNAME TestDB 783 | * fmcsadmin close -p PASSWORD TestDB 784 | * fmcsadmin close -u USERNAME -p PASSWORD TestDB 785 | * fmcsadmin close -u USERNAME -p PASSWORD -y TestDB 786 | * fmcsadmin close -m "Test Message" TestDB 787 | * fmcsadmin close -m "Test Message" -y TestDB 788 | * etc. 789 | */ 790 | expected = []string{"close", "1"} 791 | args = strings.Split("fmcsadmin close 1", " ") 792 | cmdArgs, resultFlags, _ = getFlags(args, flags) 793 | assert.Equal(t, expected, cmdArgs) 794 | 795 | expected = []string{"close", "1", "2"} 796 | args = strings.Split("fmcsadmin close 1 2", " ") 797 | cmdArgs, resultFlags, _ = getFlags(args, flags) 798 | assert.Equal(t, expected, cmdArgs) 799 | 800 | expected = []string{"close", "TestDB"} 801 | args = strings.Split("fmcsadmin close TestDB", " ") 802 | cmdArgs, resultFlags, _ = getFlags(args, flags) 803 | assert.Equal(t, false, resultFlags.yesFlag) 804 | assert.Equal(t, expected, cmdArgs) 805 | 806 | expected = []string{"close", "TestDB", "FMServer_Sample"} 807 | args = strings.Split("fmcsadmin close TestDB FMServer_Sample", " ") 808 | cmdArgs, resultFlags, _ = getFlags(args, flags) 809 | assert.Equal(t, false, resultFlags.yesFlag) 810 | assert.Equal(t, expected, cmdArgs) 811 | 812 | expected = []string{"close", "TestDB"} 813 | args = strings.Split("fmcsadmin --fqdn example.jp close TestDB", " ") 814 | cmdArgs, resultFlags, _ = getFlags(args, flags) 815 | assert.Equal(t, "example.jp", resultFlags.fqdn) 816 | assert.Equal(t, expected, cmdArgs) 817 | 818 | expected = []string{"close", "TestDB"} 819 | args = strings.Split("fmcsadmin -y close TestDB", " ") 820 | cmdArgs, resultFlags, _ = getFlags(args, flags) 821 | assert.Equal(t, true, resultFlags.yesFlag) 822 | assert.Equal(t, expected, cmdArgs) 823 | 824 | expected = []string{"close", "TestDB", "FMServer_Sample"} 825 | args = strings.Split("fmcsadmin -y close TestDB FMServer_Sample", " ") 826 | cmdArgs, resultFlags, _ = getFlags(args, flags) 827 | assert.Equal(t, true, resultFlags.yesFlag) 828 | assert.Equal(t, expected, cmdArgs) 829 | 830 | expected = []string{"close", "TestDB"} 831 | args = strings.Split("fmcsadmin close TestDB -y", " ") 832 | cmdArgs, resultFlags, _ = getFlags(args, flags) 833 | assert.Equal(t, true, resultFlags.yesFlag) 834 | assert.Equal(t, expected, cmdArgs) 835 | 836 | expected = []string{"close", "TestDB", "FMServer_Sample"} 837 | args = strings.Split("fmcsadmin close TestDB FMServer_Sample -y", " ") 838 | cmdArgs, resultFlags, _ = getFlags(args, flags) 839 | assert.Equal(t, true, resultFlags.yesFlag) 840 | assert.Equal(t, expected, cmdArgs) 841 | 842 | expected = []string{"close", "TestDB"} 843 | args = strings.Split("fmcsadmin close -y TestDB", " ") 844 | cmdArgs, resultFlags, _ = getFlags(args, flags) 845 | assert.Equal(t, true, resultFlags.yesFlag) 846 | assert.Equal(t, expected, cmdArgs) 847 | 848 | expected = []string{"close", "TestDB", "FMServer_Sample"} 849 | args = strings.Split("fmcsadmin close -y TestDB FMServer_Sample", " ") 850 | cmdArgs, resultFlags, _ = getFlags(args, flags) 851 | assert.Equal(t, true, resultFlags.yesFlag) 852 | assert.Equal(t, expected, cmdArgs) 853 | 854 | expected = []string{"close", "TestDB"} 855 | args = strings.Split("fmcsadmin close -u USERNAME TestDB", " ") 856 | cmdArgs, resultFlags, _ = getFlags(args, flags) 857 | assert.Equal(t, "USERNAME", resultFlags.username) 858 | assert.Equal(t, expected, cmdArgs) 859 | 860 | expected = []string{"close", "TestDB"} 861 | args = strings.Split("fmcsadmin close -p PASSWORD TestDB", " ") 862 | cmdArgs, resultFlags, _ = getFlags(args, flags) 863 | assert.Equal(t, "PASSWORD", resultFlags.password) 864 | assert.Equal(t, expected, cmdArgs) 865 | 866 | expected = []string{"close", "TestDB"} 867 | args = strings.Split("fmcsadmin close -u USERNAME -p PASSWORD TestDB", " ") 868 | cmdArgs, resultFlags, _ = getFlags(args, flags) 869 | assert.Equal(t, "USERNAME", resultFlags.username) 870 | assert.Equal(t, "PASSWORD", resultFlags.password) 871 | assert.Equal(t, expected, cmdArgs) 872 | 873 | expected = []string{"close", "TestDB"} 874 | args = strings.Split("fmcsadmin close -u USERNAME -p PASSWORD -y TestDB", " ") 875 | cmdArgs, resultFlags, _ = getFlags(args, flags) 876 | assert.Equal(t, "USERNAME", resultFlags.username) 877 | assert.Equal(t, "PASSWORD", resultFlags.password) 878 | assert.Equal(t, true, resultFlags.yesFlag) 879 | assert.Equal(t, expected, cmdArgs) 880 | 881 | expected = []string{"close", "TestDB"} 882 | args = strings.Split("fmcsadmin close -m Message TestDB", " ") 883 | cmdArgs, resultFlags, _ = getFlags(args, flags) 884 | assert.Equal(t, "Message", resultFlags.message) 885 | assert.Equal(t, expected, cmdArgs) 886 | 887 | expected = []string{"close", "TestDB"} 888 | args = strings.Split("fmcsadmin close -m Message -y TestDB", " ") 889 | cmdArgs, resultFlags, _ = getFlags(args, flags) 890 | assert.Equal(t, "Message", resultFlags.message) 891 | assert.Equal(t, true, resultFlags.yesFlag) 892 | assert.Equal(t, expected, cmdArgs) 893 | 894 | /* 895 | * delete 896 | * Usage: fmcsadmin DELETE [TYPE] [SCHEDULE_NUMBER] 897 | * 898 | * fmcsadmin delete schedule 2 899 | * fmcsadmin delete -y schedule 2 900 | * fmcsadmin --fqdn example.jp delete schedule 2 901 | * fmcsadmin --fqdn example.jp delete -y schedule 2 902 | * fmcsadmin --fqdn example.jp -u USERNAME delete schedule 2 903 | * fmcsadmin --fqdn example.jp -u USERNAME delete -y schedule 2 904 | * fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD delete schedule 2 905 | * fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD delete -y schedule 2 906 | */ 907 | expected = []string{"delete", "schedule", "2"} 908 | args = strings.Split("fmcsadmin delete schedule 2", " ") 909 | cmdArgs, resultFlags, _ = getFlags(args, flags) 910 | assert.Equal(t, expected, cmdArgs) 911 | 912 | expected = []string{"delete", "schedule", "2"} 913 | args = strings.Split("fmcsadmin delete -y schedule 2", " ") 914 | cmdArgs, resultFlags, _ = getFlags(args, flags) 915 | assert.Equal(t, true, resultFlags.yesFlag) 916 | assert.Equal(t, expected, cmdArgs) 917 | 918 | expected = []string{"delete", "schedule", "2"} 919 | args = strings.Split("fmcsadmin --fqdn example.jp delete schedule 2", " ") 920 | cmdArgs, resultFlags, _ = getFlags(args, flags) 921 | assert.Equal(t, "example.jp", resultFlags.fqdn) 922 | assert.Equal(t, expected, cmdArgs) 923 | 924 | expected = []string{"delete", "schedule", "2"} 925 | args = strings.Split("fmcsadmin --fqdn example.jp delete -y schedule 2", " ") 926 | cmdArgs, resultFlags, _ = getFlags(args, flags) 927 | assert.Equal(t, "example.jp", resultFlags.fqdn) 928 | assert.Equal(t, true, resultFlags.yesFlag) 929 | assert.Equal(t, expected, cmdArgs) 930 | 931 | expected = []string{"delete", "schedule", "2"} 932 | args = strings.Split("fmcsadmin --fqdn example.jp -u USERNAME delete schedule 2", " ") 933 | cmdArgs, resultFlags, _ = getFlags(args, flags) 934 | assert.Equal(t, "example.jp", resultFlags.fqdn) 935 | assert.Equal(t, "USERNAME", resultFlags.username) 936 | assert.Equal(t, expected, cmdArgs) 937 | 938 | expected = []string{"delete", "schedule", "2"} 939 | args = strings.Split("fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD delete schedule 2", " ") 940 | cmdArgs, resultFlags, _ = getFlags(args, flags) 941 | assert.Equal(t, "example.jp", resultFlags.fqdn) 942 | assert.Equal(t, "USERNAME", resultFlags.username) 943 | assert.Equal(t, "PASSWORD", resultFlags.password) 944 | assert.Equal(t, expected, cmdArgs) 945 | 946 | expected = []string{"delete", "schedule", "2"} 947 | args = strings.Split("fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD -y delete schedule 2", " ") 948 | cmdArgs, resultFlags, _ = getFlags(args, flags) 949 | assert.Equal(t, "example.jp", resultFlags.fqdn) 950 | assert.Equal(t, "USERNAME", resultFlags.username) 951 | assert.Equal(t, "PASSWORD", resultFlags.password) 952 | assert.Equal(t, true, resultFlags.yesFlag) 953 | assert.Equal(t, expected, cmdArgs) 954 | 955 | /* 956 | * disable 957 | * Usage: fmcsadmin DISABLE [TYPE] [SCHEDULE_NUMBER] 958 | * 959 | * fmcsadmin disable schedule 1 960 | * fmcsadmin disable -y schedule 1 961 | * fmcsadmin --fqdn example.jp disable schedule 1 962 | * fmcsadmin --fqdn example.jp disable -y schedule 1 963 | * fmcsadmin --fqdn example.jp -u USERNAME disable schedule 1 964 | * fmcsadmin --fqdn example.jp -u USERNAME disable -y schedule 1 965 | * fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD disable schedule 1 966 | * fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD disable -y schedule 1 967 | */ 968 | expected = []string{"disable", "schedule", "1"} 969 | args = strings.Split("fmcsadmin disable schedule 1", " ") 970 | cmdArgs, resultFlags, _ = getFlags(args, flags) 971 | assert.Equal(t, expected, cmdArgs) 972 | 973 | expected = []string{"disable", "schedule", "1"} 974 | args = strings.Split("fmcsadmin disable -y schedule 1", " ") 975 | cmdArgs, resultFlags, _ = getFlags(args, flags) 976 | assert.Equal(t, true, resultFlags.yesFlag) 977 | assert.Equal(t, expected, cmdArgs) 978 | 979 | expected = []string{"disable", "schedule", "1"} 980 | args = strings.Split("fmcsadmin --fqdn example.jp disable schedule 1", " ") 981 | cmdArgs, resultFlags, _ = getFlags(args, flags) 982 | assert.Equal(t, "example.jp", resultFlags.fqdn) 983 | assert.Equal(t, expected, cmdArgs) 984 | 985 | expected = []string{"disable", "schedule", "1"} 986 | args = strings.Split("fmcsadmin --fqdn example.jp disable -y schedule 1", " ") 987 | cmdArgs, resultFlags, _ = getFlags(args, flags) 988 | assert.Equal(t, "example.jp", resultFlags.fqdn) 989 | assert.Equal(t, true, resultFlags.yesFlag) 990 | assert.Equal(t, expected, cmdArgs) 991 | 992 | expected = []string{"disable", "schedule", "1"} 993 | args = strings.Split("fmcsadmin --fqdn example.jp -u USERNAME disable schedule 1", " ") 994 | cmdArgs, resultFlags, _ = getFlags(args, flags) 995 | assert.Equal(t, "example.jp", resultFlags.fqdn) 996 | assert.Equal(t, "USERNAME", resultFlags.username) 997 | assert.Equal(t, expected, cmdArgs) 998 | 999 | expected = []string{"disable", "schedule", "1"} 1000 | args = strings.Split("fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD disable schedule 1", " ") 1001 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1002 | assert.Equal(t, "example.jp", resultFlags.fqdn) 1003 | assert.Equal(t, "USERNAME", resultFlags.username) 1004 | assert.Equal(t, "PASSWORD", resultFlags.password) 1005 | assert.Equal(t, expected, cmdArgs) 1006 | 1007 | expected = []string{"disable", "schedule", "1"} 1008 | args = strings.Split("fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD -y disable schedule 1", " ") 1009 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1010 | assert.Equal(t, "example.jp", resultFlags.fqdn) 1011 | assert.Equal(t, "USERNAME", resultFlags.username) 1012 | assert.Equal(t, "PASSWORD", resultFlags.password) 1013 | assert.Equal(t, true, resultFlags.yesFlag) 1014 | assert.Equal(t, expected, cmdArgs) 1015 | 1016 | /* 1017 | * disconnect 1018 | * Usage: fmcsadmin DISCONNECT CLIENT [CLIENT_NUMBER] [options] 1019 | * 1020 | * fmcsadmin disconnect client 1021 | * fmcsadmin disconnect client -y 1022 | * fmcsadmin disconnect client -m "Message" 1023 | * fmcsadmin disconnect client -m "Message" -y 1024 | * fmcsadmin disconnect client -t 90 1025 | * fmcsadmin disconnect client -t 90 -y 1026 | * fmcsadmin disconnect client -m "Message" -t 90 1027 | * fmcsadmin disconnect client -m "Message" -t 90 -y 1028 | * fmcsadmin disconnect client 1 1029 | * fmcsadmin disconnect client 1 -y 1030 | * fmcsadmin disconnect client 1 -m "Message" 1031 | * fmcsadmin disconnect client 1 -m "Message" -y 1032 | * fmcsadmin disconnect client 1 -t 90 1033 | * fmcsadmin disconnect client 1 -t 90 -y 1034 | * fmcsadmin disconnect client 1 -m "Message" -t 90 1035 | * fmcsadmin disconnect client 1 -m "Message" -t 90 -y 1036 | * fmcsadmin --fqdn example.jp disconnect client 1037 | * fmcsadmin --fqdn example.jp disconnect -y client 1038 | * fmcsadmin --fqdn example.jp -u USERNAME disconnect client 1039 | * fmcsadmin --fqdn example.jp -u USERNAME disconnect -y client 1040 | * fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD disconnect client 1041 | * fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD disconnect -y client 1042 | * etc. 1043 | */ 1044 | expected = []string{"disconnect", "client"} 1045 | args = strings.Split("fmcsadmin disconnect client", " ") 1046 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1047 | assert.Equal(t, expected, cmdArgs) 1048 | 1049 | expected = []string{"disconnect", "client"} 1050 | args = strings.Split("fmcsadmin disconnect client -y", " ") 1051 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1052 | assert.Equal(t, true, resultFlags.yesFlag) 1053 | assert.Equal(t, expected, cmdArgs) 1054 | 1055 | expected = []string{"disconnect", "client"} 1056 | args = strings.Split("fmcsadmin disconnect client -m Message", " ") 1057 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1058 | assert.Equal(t, "Message", resultFlags.message) 1059 | assert.Equal(t, expected, cmdArgs) 1060 | 1061 | expected = []string{"disconnect", "client"} 1062 | args = strings.Split("fmcsadmin disconnect client -m Message -y", " ") 1063 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1064 | assert.Equal(t, "Message", resultFlags.message) 1065 | assert.Equal(t, true, resultFlags.yesFlag) 1066 | assert.Equal(t, expected, cmdArgs) 1067 | 1068 | expected = []string{"disconnect", "client"} 1069 | args = strings.Split("fmcsadmin disconnect client -m Message -t 90", " ") 1070 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1071 | assert.Equal(t, "Message", resultFlags.message) 1072 | assert.Equal(t, 90, resultFlags.graceTime) 1073 | assert.Equal(t, expected, cmdArgs) 1074 | 1075 | expected = []string{"disconnect", "client"} 1076 | args = strings.Split("fmcsadmin disconnect client -m Message -t 90 -y", " ") 1077 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1078 | assert.Equal(t, "Message", resultFlags.message) 1079 | assert.Equal(t, 90, resultFlags.graceTime) 1080 | assert.Equal(t, true, resultFlags.yesFlag) 1081 | assert.Equal(t, expected, cmdArgs) 1082 | 1083 | expected = []string{"disconnect", "client", "1"} 1084 | args = strings.Split("fmcsadmin disconnect client 1", " ") 1085 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1086 | assert.Equal(t, expected, cmdArgs) 1087 | 1088 | expected = []string{"disconnect", "client", "1"} 1089 | args = strings.Split("fmcsadmin disconnect client 1 -y", " ") 1090 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1091 | assert.Equal(t, true, resultFlags.yesFlag) 1092 | assert.Equal(t, expected, cmdArgs) 1093 | 1094 | expected = []string{"disconnect", "client", "1"} 1095 | args = strings.Split("fmcsadmin disconnect client 1 -m Message", " ") 1096 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1097 | assert.Equal(t, "Message", resultFlags.message) 1098 | assert.Equal(t, expected, cmdArgs) 1099 | 1100 | expected = []string{"disconnect", "client", "1"} 1101 | args = strings.Split("fmcsadmin disconnect client 1 -m Message -y", " ") 1102 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1103 | assert.Equal(t, "Message", resultFlags.message) 1104 | assert.Equal(t, true, resultFlags.yesFlag) 1105 | assert.Equal(t, expected, cmdArgs) 1106 | 1107 | expected = []string{"disconnect", "client", "1"} 1108 | args = strings.Split("fmcsadmin disconnect client 1 -m Message -t 90", " ") 1109 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1110 | assert.Equal(t, "Message", resultFlags.message) 1111 | assert.Equal(t, 90, resultFlags.graceTime) 1112 | assert.Equal(t, expected, cmdArgs) 1113 | 1114 | expected = []string{"disconnect", "client", "1"} 1115 | args = strings.Split("fmcsadmin disconnect client 1 -m Message -t 90 -y", " ") 1116 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1117 | assert.Equal(t, "Message", resultFlags.message) 1118 | assert.Equal(t, 90, resultFlags.graceTime) 1119 | assert.Equal(t, true, resultFlags.yesFlag) 1120 | assert.Equal(t, expected, cmdArgs) 1121 | 1122 | /* 1123 | * enable 1124 | * Usage: fmcsadmin ENABLE [TYPE] [SCHEDULE_NUMBER] 1125 | * 1126 | * fmcsadmin enable schedule 2 1127 | * fmcsadmin -u USERNAME enable schedule 2 1128 | * fmcsadmin -u USERNAME -p PASSWORD enable schedule 2 1129 | * fmcsadmin --fqdn example.jp enable schedule 2 1130 | * fmcsadmin --fqdn example.jp -u USERNAME enable schedule 2 1131 | * fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD enable schedule 2 1132 | */ 1133 | expected = []string{"enable", "schedule", "2"} 1134 | args = strings.Split("fmcsadmin enable schedule 2", " ") 1135 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1136 | assert.Equal(t, expected, cmdArgs) 1137 | 1138 | expected = []string{"enable", "schedule", "2"} 1139 | args = strings.Split("fmcsadmin --fqdn example.jp enable schedule 2", " ") 1140 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1141 | assert.Equal(t, "example.jp", resultFlags.fqdn) 1142 | assert.Equal(t, expected, cmdArgs) 1143 | 1144 | /* 1145 | * get 1146 | * Usage: fmcsadmin GET BACKUPTIME [ID] 1147 | * fmcsadmin GET CONFIG_TYPE [NAME1 NAME2 ...] 1148 | * 1149 | * fmcsadmin get backuptime 1150 | * fmcsadmin get backuptime 2 1151 | * fmcsadmin get serverconfig 1152 | * fmcsadmin get serverconfig hostedfiles scriptsessions 1153 | * fmcsadmin get serverconfig scriptsessions hostedfiles 1154 | * fmcsadmin get cwpconfig 1155 | * fmcsadmin get cwpconfig enablexml 1156 | * fmcsadmin get cwpconfig enablephp usefmphp 1157 | * fmcsadmin get cwpconfig usefmphp enablephp 1158 | * fmcsadmin get serverprefs 1159 | * fmcsadmin get serverprefs maxguests maxfiles 1160 | * fmcsadmin get serverprefs maxfiles maxguests 1161 | * fmcsadmin get serverprefs AuthenticatedStream 1162 | * fmcsadmin get serverprefs ParallelBackupEnabled 1163 | * fmcsadmin get serverprefs PersistCacheEnabled 1164 | * fmcsadmin get serverprefs SyncPersistCache 1165 | * fmcsadmin get serverprefs DatabaseServerAutoRestart 1166 | * fmcsadmin get serverprefs BlockNewUsersEnabled 1167 | * fmcsadmin get serverprefs EnableHttpProtocolNetwork 1168 | * fmcsadmin get serverprefs OnlyOpenLastOpenedDatabases 1169 | * fmcsadmin --fqdn example.jp get backuptime 1170 | * fmcsadmin --fqdn example.jp -u USERNAME get backuptime 1171 | * fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD get backuptime 1172 | * etc. 1173 | */ 1174 | 1175 | /* 1176 | * help 1177 | * Usage: fmcsadmin HELP COMMANDS 1178 | * fmcsadmin HELP [COMMAND] 1179 | * fmcsadmin HELP OPTIONS 1180 | * 1181 | * fmcsadmin help 1182 | * fmcsadmin help commands 1183 | * fmcsadmin help options 1184 | * fmcsadmin help certificate 1185 | * fmcsadmin help close 1186 | * fmcsadmin help delete 1187 | * fmcsadmin help disable 1188 | * fmcsadmin help disconnect 1189 | * fmcsadmin help enable 1190 | * fmcsadmin help get 1191 | * fmcsadmin help help 1192 | * fmcsadmin help list 1193 | * fmcsadmin help open 1194 | * fmcsadmin help pause 1195 | * fmcsadmin help run 1196 | * fmcsadmin help send 1197 | * fmcsadmin help set 1198 | * fmcsadmin help status 1199 | */ 1200 | expected = []string{"help"} 1201 | args = strings.Split("fmcsadmin help", " ") 1202 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1203 | assert.Equal(t, expected, cmdArgs) 1204 | 1205 | /* 1206 | * list 1207 | * Usage: fmcsadmin LIST [TYPE] [options] 1208 | * 1209 | * fmcsadmin list clients 1210 | * fmcsadmin list clients -s 1211 | * fmcsadmin list files 1212 | * fmcsadmin list files -s 1213 | * fmcsadmin list plugins 1214 | * fmcsadmin list plugins -s 1215 | * fmcsadmin list schedules 1216 | * fmcsadmin list schedules -s 1217 | * fmcsadmin --fqdn example.jp list clients 1218 | * fmcsadmin --fqdn example.jp list clients -s 1219 | * fmcsadmin --fqdn example.jp list files 1220 | * fmcsadmin --fqdn example.jp list files -s 1221 | * fmcsadmin --fqdn example.jp list plugins 1222 | * fmcsadmin --fqdn example.jp list plugins -s 1223 | * fmcsadmin --fqdn example.jp list schedules 1224 | * fmcsadmin --fqdn example.jp list schedules -s 1225 | * fmcsadmin -u USERNAME list clients 1226 | * fmcsadmin -u USERNAME list clients -s 1227 | * fmcsadmin -u USERNAME list files 1228 | * fmcsadmin -u USERNAME list files -s 1229 | * fmcsadmin -u USERNAME list plugins 1230 | * fmcsadmin -u USERNAME list plugins -s 1231 | * fmcsadmin -u USERNAME list schedules 1232 | * fmcsadmin -u USERNAME list schedules -s 1233 | * fmcsadmin -p PASSWORD list clients 1234 | * fmcsadmin -p PASSWORD list clients -s 1235 | * fmcsadmin -p PASSWORD list files 1236 | * fmcsadmin -p PASSWORD list files -s 1237 | * fmcsadmin -p PASSWORD list plugins 1238 | * fmcsadmin -p PASSWORD list plugins -s 1239 | * fmcsadmin -p PASSWORD list schedules 1240 | * fmcsadmin -p PASSWORD list schedules -s 1241 | * fmcsadmin -u USERNAME -p PASSWORD list clients 1242 | * fmcsadmin -u USERNAME -p PASSWORD list clients -s 1243 | * fmcsadmin -u USERNAME -p PASSWORD list files 1244 | * fmcsadmin -u USERNAME -p PASSWORD list files -s 1245 | * fmcsadmin -u USERNAME -p PASSWORD list plugins 1246 | * fmcsadmin -u USERNAME -p PASSWORD list plugins -s 1247 | * fmcsadmin -u USERNAME -p PASSWORD list schedules 1248 | * fmcsadmin -u USERNAME -p PASSWORD list schedules -s 1249 | */ 1250 | // list clients 1251 | expected = []string{"list", "clients"} 1252 | args = strings.Split("fmcsadmin list clients", " ") 1253 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1254 | assert.Equal(t, false, resultFlags.statsFlag) 1255 | assert.Equal(t, expected, cmdArgs) 1256 | 1257 | expected = []string{"list", "clients"} 1258 | args = strings.Split("fmcsadmin -s list clients", " ") 1259 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1260 | assert.Equal(t, true, resultFlags.statsFlag) 1261 | assert.Equal(t, expected, cmdArgs) 1262 | 1263 | expected = []string{"list", "clients"} 1264 | args = strings.Split("fmcsadmin --stats list clients", " ") 1265 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1266 | assert.Equal(t, true, resultFlags.statsFlag) 1267 | assert.Equal(t, expected, cmdArgs) 1268 | 1269 | expected = []string{"list", "clients"} 1270 | args = strings.Split("fmcsadmin list clients -s", " ") 1271 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1272 | assert.Equal(t, true, resultFlags.statsFlag) 1273 | assert.Equal(t, expected, cmdArgs) 1274 | 1275 | expected = []string{"list", "clients"} 1276 | args = strings.Split("fmcsadmin list clients --stats", " ") 1277 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1278 | assert.Equal(t, true, resultFlags.statsFlag) 1279 | assert.Equal(t, expected, cmdArgs) 1280 | 1281 | expected = []string{"list", "clients"} 1282 | args = strings.Split("fmcsadmin list -s clients", " ") 1283 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1284 | assert.Equal(t, true, resultFlags.statsFlag) 1285 | assert.Equal(t, expected, cmdArgs) 1286 | 1287 | expected = []string{"list", "clients"} 1288 | args = strings.Split("fmcsadmin list --stats clients", " ") 1289 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1290 | assert.Equal(t, true, resultFlags.statsFlag) 1291 | assert.Equal(t, expected, cmdArgs) 1292 | 1293 | // list files 1294 | expected = []string{"list", "files"} 1295 | args = strings.Split("fmcsadmin list files", " ") 1296 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1297 | assert.Equal(t, false, resultFlags.statsFlag) 1298 | assert.Equal(t, expected, cmdArgs) 1299 | 1300 | expected = []string{"list", "files"} 1301 | args = strings.Split("fmcsadmin -s list files", " ") 1302 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1303 | assert.Equal(t, true, resultFlags.statsFlag) 1304 | assert.Equal(t, expected, cmdArgs) 1305 | 1306 | expected = []string{"list", "files"} 1307 | args = strings.Split("fmcsadmin --stats list files", " ") 1308 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1309 | assert.Equal(t, true, resultFlags.statsFlag) 1310 | assert.Equal(t, expected, cmdArgs) 1311 | 1312 | expected = []string{"list", "files"} 1313 | args = strings.Split("fmcsadmin list files -s", " ") 1314 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1315 | assert.Equal(t, true, resultFlags.statsFlag) 1316 | assert.Equal(t, expected, cmdArgs) 1317 | 1318 | expected = []string{"list", "files"} 1319 | args = strings.Split("fmcsadmin list files --stats", " ") 1320 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1321 | assert.Equal(t, true, resultFlags.statsFlag) 1322 | assert.Equal(t, expected, cmdArgs) 1323 | 1324 | expected = []string{"list", "files"} 1325 | args = strings.Split("fmcsadmin list -s files", " ") 1326 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1327 | assert.Equal(t, true, resultFlags.statsFlag) 1328 | assert.Equal(t, expected, cmdArgs) 1329 | 1330 | expected = []string{"list", "files"} 1331 | args = strings.Split("fmcsadmin list --stats files", " ") 1332 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1333 | assert.Equal(t, true, resultFlags.statsFlag) 1334 | assert.Equal(t, expected, cmdArgs) 1335 | 1336 | // list plugins 1337 | expected = []string{"list", "plugins"} 1338 | args = strings.Split("fmcsadmin list plugins", " ") 1339 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1340 | assert.Equal(t, false, resultFlags.statsFlag) 1341 | assert.Equal(t, expected, cmdArgs) 1342 | 1343 | expected = []string{"list", "plugins"} 1344 | args = strings.Split("fmcsadmin -s list plugins", " ") 1345 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1346 | assert.Equal(t, true, resultFlags.statsFlag) 1347 | assert.Equal(t, expected, cmdArgs) 1348 | 1349 | expected = []string{"list", "plugins"} 1350 | args = strings.Split("fmcsadmin --stats list plugins", " ") 1351 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1352 | assert.Equal(t, true, resultFlags.statsFlag) 1353 | assert.Equal(t, expected, cmdArgs) 1354 | 1355 | expected = []string{"list", "plugins"} 1356 | args = strings.Split("fmcsadmin list plugins -s", " ") 1357 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1358 | assert.Equal(t, true, resultFlags.statsFlag) 1359 | assert.Equal(t, expected, cmdArgs) 1360 | 1361 | expected = []string{"list", "plugins"} 1362 | args = strings.Split("fmcsadmin list plugins --stats", " ") 1363 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1364 | assert.Equal(t, true, resultFlags.statsFlag) 1365 | assert.Equal(t, expected, cmdArgs) 1366 | 1367 | expected = []string{"list", "plugins"} 1368 | args = strings.Split("fmcsadmin list -s plugins", " ") 1369 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1370 | assert.Equal(t, true, resultFlags.statsFlag) 1371 | assert.Equal(t, expected, cmdArgs) 1372 | 1373 | expected = []string{"list", "plugins"} 1374 | args = strings.Split("fmcsadmin list --stats plugins", " ") 1375 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1376 | assert.Equal(t, true, resultFlags.statsFlag) 1377 | assert.Equal(t, expected, cmdArgs) 1378 | 1379 | // list schedules 1380 | expected = []string{"list", "schedules"} 1381 | args = strings.Split("fmcsadmin list schedules", " ") 1382 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1383 | assert.Equal(t, false, resultFlags.statsFlag) 1384 | assert.Equal(t, expected, cmdArgs) 1385 | 1386 | expected = []string{"list", "schedules"} 1387 | args = strings.Split("fmcsadmin -s list schedules", " ") 1388 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1389 | assert.Equal(t, true, resultFlags.statsFlag) 1390 | assert.Equal(t, expected, cmdArgs) 1391 | 1392 | expected = []string{"list", "schedules"} 1393 | args = strings.Split("fmcsadmin --stats list schedules", " ") 1394 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1395 | assert.Equal(t, true, resultFlags.statsFlag) 1396 | assert.Equal(t, expected, cmdArgs) 1397 | 1398 | expected = []string{"list", "schedules"} 1399 | args = strings.Split("fmcsadmin list schedules -s", " ") 1400 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1401 | assert.Equal(t, true, resultFlags.statsFlag) 1402 | assert.Equal(t, expected, cmdArgs) 1403 | 1404 | expected = []string{"list", "schedules"} 1405 | args = strings.Split("fmcsadmin list schedules --stats", " ") 1406 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1407 | assert.Equal(t, true, resultFlags.statsFlag) 1408 | assert.Equal(t, expected, cmdArgs) 1409 | 1410 | expected = []string{"list", "schedules"} 1411 | args = strings.Split("fmcsadmin list -s schedules", " ") 1412 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1413 | assert.Equal(t, true, resultFlags.statsFlag) 1414 | assert.Equal(t, expected, cmdArgs) 1415 | 1416 | expected = []string{"list", "schedules"} 1417 | args = strings.Split("fmcsadmin list --stats schedules", " ") 1418 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1419 | assert.Equal(t, true, resultFlags.statsFlag) 1420 | assert.Equal(t, expected, cmdArgs) 1421 | 1422 | /* 1423 | * open 1424 | * Usage: fmcsadmin OPEN [options] [FILE...] [PATH...] 1425 | * 1426 | * fmcsadmin open 1427 | * fmcsadmin open 1 1428 | * fmcsadmin open 1 2 1429 | * fmcsadmin open TestDB 1430 | * fmcsadmin open TestDB.fmp12 1431 | * fmcsadmin open "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB" 1432 | * fmcsadmin open "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12" 1433 | * fmcsadmin open "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB" 1434 | * fmcsadmin open "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12" 1435 | * fmcsadmin open "/opt/FileMaker/FileMaker Server/Data/Databases/" 1436 | * fmcsadmin open "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/" 1437 | * fmcsadmin open TestDB FMServer_Sample 1438 | * fmcsadmin --fqdn example.jp open TestDB 1439 | * fmcsadmin open -y TestDB 1440 | * fmcsadmin open -u USERNAME TestDB 1441 | * fmcsadmin open -p PASSWORD TestDB 1442 | * fmcsadmin open -u USERNAME -p PASSWORD TestDB 1443 | * fmcsadmin open --key ENCRYPTPASS TestDB 1444 | * fmcsadmin open --key ENCRYPTPASS --savekey TestDB 1445 | */ 1446 | expected = []string{"open", "TestDB"} 1447 | args = strings.Split("fmcsadmin open TestDB", " ") 1448 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1449 | assert.Equal(t, "", resultFlags.key) 1450 | assert.Equal(t, expected, cmdArgs) 1451 | 1452 | expected = []string{"open", "TestDB"} 1453 | args = strings.Split("fmcsadmin --key KEY open TestDB", " ") 1454 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1455 | assert.Equal(t, "KEY", resultFlags.key) 1456 | assert.Equal(t, expected, cmdArgs) 1457 | 1458 | expected = []string{"open", "TestDB"} 1459 | args = strings.Split("fmcsadmin open TestDB --key KEY", " ") 1460 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1461 | assert.Equal(t, "KEY", resultFlags.key) 1462 | assert.Equal(t, expected, cmdArgs) 1463 | 1464 | expected = []string{"open", "TestDB"} 1465 | args = strings.Split("fmcsadmin open --key KEY TestDB", " ") 1466 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1467 | assert.Equal(t, "KEY", resultFlags.key) 1468 | assert.Equal(t, expected, cmdArgs) 1469 | 1470 | expected = []string{"open", "TestDB"} 1471 | args = strings.Split("fmcsadmin open --key KEY TestDB", " ") 1472 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1473 | assert.Equal(t, "KEY", resultFlags.key) 1474 | assert.Equal(t, expected, cmdArgs) 1475 | 1476 | expected = []string{"open"} 1477 | args = strings.Split("fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD open --key KEY", " ") 1478 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1479 | assert.Equal(t, "example.jp", resultFlags.fqdn) 1480 | assert.Equal(t, "USERNAME", resultFlags.username) 1481 | assert.Equal(t, "PASSWORD", resultFlags.password) 1482 | assert.Equal(t, "KEY", resultFlags.key) 1483 | assert.Equal(t, expected, cmdArgs) 1484 | 1485 | expected = []string{"open"} 1486 | args = strings.Split("fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD open --key KEY --savekey", " ") 1487 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1488 | assert.Equal(t, "example.jp", resultFlags.fqdn) 1489 | assert.Equal(t, "USERNAME", resultFlags.username) 1490 | assert.Equal(t, "PASSWORD", resultFlags.password) 1491 | assert.Equal(t, "KEY", resultFlags.key) 1492 | assert.Equal(t, expected, cmdArgs) 1493 | 1494 | /* 1495 | * pause 1496 | * Usage: fmcsadmin PAUSE [FILE...] [PATH...] 1497 | * 1498 | * fmcsadmin pause 1499 | * fmcsadmin pause 1 1500 | * fmcsadmin pause 1 2 1501 | * fmcsadmin pause TestDB 1502 | * fmcsadmin pause TestDB.fmp12 1503 | * fmcsadmin pause "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB" 1504 | * fmcsadmin pause "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12" 1505 | * fmcsadmin pause "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB" 1506 | * fmcsadmin pause "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12" 1507 | * fmcsadmin pause "/opt/FileMaker/FileMaker Server/Data/Databases/" 1508 | * fmcsadmin pause "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/" 1509 | * fmcsadmin pause TestDB FMServer_Sample 1510 | * fmcsadmin --fqdn example.jp pause TestDB 1511 | * fmcsadmin pause -u USERNAME TestDB 1512 | * fmcsadmin pause -p PASSWORD TestDB 1513 | * fmcsadmin pause -u USERNAME -p PASSWORD TestDB 1514 | */ 1515 | expected = []string{"pause", "TestDB"} 1516 | args = strings.Split("fmcsadmin pause TestDB", " ") 1517 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1518 | assert.Equal(t, expected, cmdArgs) 1519 | 1520 | expected = []string{"pause", "TestDB", "FMServer_Sample"} 1521 | args = strings.Split("fmcsadmin pause TestDB FMServer_Sample", " ") 1522 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1523 | assert.Equal(t, expected, cmdArgs) 1524 | 1525 | /* 1526 | * remove 1527 | * Usage: fmcsadmin REMOVE [FILE...] [PATH...] 1528 | * 1529 | * fmcsadmin remove 1530 | * fmcsadmin remove 1 1531 | * fmcsadmin remove 1 2 1532 | * fmcsadmin remove TestDB 1533 | * fmcsadmin remove TestDB.fmp12 1534 | * fmcsadmin remove 11.fmp12 1535 | * fmcsadmin remove "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB" 1536 | * fmcsadmin remove "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12" 1537 | * fmcsadmin remove "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB" 1538 | * fmcsadmin remove "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12" 1539 | * fmcsadmin remove "/opt/FileMaker/FileMaker Server/Data/Databases/" 1540 | * fmcsadmin remove "filemac:/Macintosh HD/Library/FileMaker Server/Data/Databases/" 1541 | * fmcsadmin remove "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/" 1542 | * fmcsadmin remove TestDB FMServer_Sample 1543 | * fmcsadmin --fqdn example.jp remove TestDB 1544 | * fmcsadmin remove -u USERNAME TestDB 1545 | * fmcsadmin remove -p PASSWORD TestDB 1546 | * fmcsadmin remove -u USERNAME -p PASSWORD TestDB 1547 | * fmcsadmin remove -u USERNAME -p PASSWORD TestDB -y 1548 | */ 1549 | expected = []string{"remove", "TestDB"} 1550 | args = strings.Split("fmcsadmin remove TestDB", " ") 1551 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1552 | assert.Equal(t, expected, cmdArgs) 1553 | 1554 | expected = []string{"remove", "TestDB", "FMServer_Sample"} 1555 | args = strings.Split("fmcsadmin remove TestDB FMServer_Sample", " ") 1556 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1557 | assert.Equal(t, expected, cmdArgs) 1558 | 1559 | /* 1560 | * resume 1561 | * Usage: fmcsadmin RESUME [FILE...] [PATH...] 1562 | * 1563 | * fmcsadmin resume 1564 | * fmcsadmin resume 1 1565 | * fmcsadmin resume 1 2 1566 | * fmcsadmin resume TestDB 1567 | * fmcsadmin resume TestDB.fmp12 1568 | * fmcsadmin resume "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB" 1569 | * fmcsadmin resume "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12" 1570 | * fmcsadmin resume "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB" 1571 | * fmcsadmin resume "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12" 1572 | * fmcsadmin resume "/opt/FileMaker/FileMaker Server/Data/Databases/" 1573 | * fmcsadmin resume "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/" 1574 | * fmcsadmin resume TestDB FMServer_Sample 1575 | * fmcsadmin --fqdn example.jp resume TestDB 1576 | * fmcsadmin resume -u USERNAME TestDB 1577 | * fmcsadmin resume -p PASSWORD TestDB 1578 | * fmcsadmin resume -u USERNAME -p PASSWORD TestDB 1579 | */ 1580 | expected = []string{"resume", "TestDB"} 1581 | args = strings.Split("fmcsadmin resume TestDB", " ") 1582 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1583 | assert.Equal(t, expected, cmdArgs) 1584 | 1585 | expected = []string{"resume", "TestDB", "FMServer_Sample"} 1586 | args = strings.Split("fmcsadmin resume TestDB FMServer_Sample", " ") 1587 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1588 | assert.Equal(t, expected, cmdArgs) 1589 | 1590 | /* 1591 | * run 1592 | * Usage: fmcsadmin RUN SCHEDULE [SCHEDULE_NUMBER] 1593 | * 1594 | * fmcsadmin run schedule 2 1595 | * fmcsadmin --fqdn example.jp run schedule 2 1596 | * fmcsadmin --fqdn example.jp -u USERNAME run schedule 2 1597 | * fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD run schedule 2 1598 | */ 1599 | expected = []string{"run", "schedule", "2"} 1600 | args = strings.Split("fmcsadmin run schedule 2", " ") 1601 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1602 | assert.Equal(t, expected, cmdArgs) 1603 | 1604 | /* 1605 | * send 1606 | * Usage: fmcsadmin SEND [options] [CLIENT_NUMBER] [FILE...] [PATH...] 1607 | * 1608 | * fmcsadmin send -m "This is a test message" 1609 | * fmcsadmin send -c 2 -m "This is a test message" 1610 | * etc. 1611 | */ 1612 | 1613 | /* 1614 | * set 1615 | * Usage: fmcsadmin SET CONFIG_TYPE [NAME1=VALUE1 NAME2=VALUE2 ...] 1616 | * 1617 | * fmcsadmin set serverconfig hostedfiles=125 scriptsessions=100 1618 | * fmcsadmin set cwpconfig enablephp=true 1619 | * fmcsadmin set cwpconfig enablexml=true 1620 | * fmcsadmin set cwpconfig encoding=UTF-8 1621 | * fmcsadmin set cwpconfig encoding=ISO-8859-1 1622 | * fmcsadmin set cwpconfig locale=en 1623 | * fmcsadmin set cwpconfig locale=ja 1624 | * fmcsadmin set cwpconfig prevalidation=false 1625 | * fmcsadmin set cwpconfig enablephp=true usefmphp=false 1626 | * fmcsadmin set cwpconfig enablephp=true usefmphp=true 1627 | * fmcsadmin --fqdn example.jp set cwpconfig enablephp=true usefmphp=true 1628 | * fmcsadmin --fqdn example.jp -u USERNAME set cwpconfig enablephp=true usefmphp=true 1629 | * fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD set cwpconfig enablephp=true usefmphp=true 1630 | * fmcsadmin set serverprefs maxguests=125 maxfiles=256 1631 | * fmcsadmin set serverprefs AuthenticatedStream=1 1632 | * fmcsadmin set serverprefs AuthenticatedStream=2 1633 | * fmcsadmin set serverprefs ParallelBackupEnabled=false 1634 | * fmcsadmin set serverprefs ParallelBackupEnabled=true 1635 | * fmcsadmin set serverprefs PersistCacheEnabled=false 1636 | * fmcsadmin set serverprefs PersistCacheEnabled=true 1637 | * fmcsadmin set serverprefs SyncPersistCache=false 1638 | * fmcsadmin set serverprefs SyncPersistCache=true 1639 | * fmcsadmin set serverprefs DatabaseServerAutoRestart=false 1640 | * fmcsadmin set serverprefs DatabaseServerAutoRestart=true 1641 | * fmcsadmin set serverprefs BlockNewUsersEnabled=false 1642 | * fmcsadmin set serverprefs BlockNewUsersEnabled=true 1643 | * fmcsadmin set serverprefs EnableHttpProtocolNetwork=false 1644 | * fmcsadmin set serverprefs EnableHttpProtocolNetwork=true 1645 | * fmcsadmin set serverprefs OnlyOpenLastOpenedDatabases=false 1646 | * fmcsadmin set serverprefs OnlyOpenLastOpenedDatabases=true 1647 | * fmcsadmin --fqdn example.jp set serverconfig hostedfiles=125 scriptsessions=100 1648 | * fmcsadmin --fqdn example.jp -u USERNAME set serverconfig hostedfiles=125 scriptsessions=100 1649 | * fmcsadmin --fqdn example.jp -u USERNAME -p PASSWORD set serverconfig hostedfiles=125 scriptsessions=100 1650 | * etc. 1651 | */ 1652 | 1653 | /* 1654 | * status 1655 | * Usage: fmcsadmin STATUS [TYPE] [CLIENT_NUMBER] [FILE...] 1656 | * 1657 | * fmcsadmin status client 1 1658 | * fmcsadmin status file TestDB 1659 | * fmcsadmin status file "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB" 1660 | * fmcsadmin status file "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12" 1661 | * fmcsadmin status file "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB" 1662 | * fmcsadmin status file "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12" 1663 | * fmcsadmin status file TestDB FMServer_Sample 1664 | */ 1665 | expected = []string{"status", "client", "1"} 1666 | args = strings.Split("fmcsadmin status client 1", " ") 1667 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1668 | assert.Equal(t, expected, cmdArgs) 1669 | 1670 | expected = []string{"status", "file", "TestDB"} 1671 | args = strings.Split("fmcsadmin status file TestDB", " ") 1672 | cmdArgs, resultFlags, _ = getFlags(args, flags) 1673 | assert.Equal(t, expected, cmdArgs) 1674 | } 1675 | 1676 | func TestOutputInvalidCommandErrorMessage(t *testing.T) { 1677 | outStream, errStream := new(bytes.Buffer), new(bytes.Buffer) 1678 | cli := &cli{outStream: outStream, errStream: errStream} 1679 | status := outputInvalidCommandErrorMessage(cli) 1680 | assert.Equal(t, 248, status) 1681 | } 1682 | 1683 | func TestGetBaseURI(t *testing.T) { 1684 | if runtime.GOOS == "linux" { 1685 | assert.Equal(t, "http://127.0.0.1:16001", getBaseURI("")) 1686 | } else if runtime.GOOS == "darwin" || runtime.GOOS == "windows" { 1687 | assert.Equal(t, "http://127.0.0.1:16001", getBaseURI("")) 1688 | } 1689 | assert.Equal(t, "https://example.jp", getBaseURI("example.jp")) 1690 | assert.Equal(t, "https://example.jp", getBaseURI("example.jp ")) 1691 | assert.Equal(t, "https://example.jp", getBaseURI(" example.jp")) 1692 | } 1693 | 1694 | func TestGetAPIBasePath(t *testing.T) { 1695 | assert.Equal(t, "/fmi/admin/api/v2", getAPIBasePath()) 1696 | } 1697 | 1698 | func TestGetServerVersionAsFloat(t *testing.T) { 1699 | version, _ := getServerVersionAsFloat("19.3.1") 1700 | assert.Equal(t, 19.3, version) 1701 | version, _ = getServerVersionAsFloat("19.3.2") 1702 | assert.Equal(t, 19.3, version) 1703 | } 1704 | 1705 | func TestComparePath(t *testing.T) { 1706 | assert.Equal(t, false, comparePath("TestDB", "TestDB2")) 1707 | 1708 | assert.Equal(t, true, comparePath("TestDB", "TestDB")) 1709 | assert.Equal(t, true, comparePath("TestDB.fmp12", "TestDB.fmp12")) 1710 | assert.Equal(t, true, comparePath("TestDB", "TestDB.fmp12")) 1711 | assert.Equal(t, true, comparePath("TestDB.fmp12", "TestDB")) 1712 | 1713 | assert.Equal(t, true, comparePath("filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/", "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/")) 1714 | 1715 | assert.Equal(t, true, comparePath("filemac:/opt/FileMaker/FileMaker Server/Data/Databases/", "filemac:/opt/FileMaker/FileMaker Server/Data/Databases/")) 1716 | 1717 | assert.Equal(t, true, comparePath("filewin:/opt/FileMaker/FileMaker Server/Data/Databases/", "filewin:/opt/FileMaker/FileMaker Server/Data/Databases/")) 1718 | 1719 | assert.Equal(t, true, comparePath("filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB", "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB")) 1720 | assert.Equal(t, true, comparePath("filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12", "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12")) 1721 | assert.Equal(t, true, comparePath("filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB", "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12")) 1722 | assert.Equal(t, true, comparePath("filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12", "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB")) 1723 | 1724 | assert.Equal(t, true, comparePath("filemac:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB", "filemac:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB")) 1725 | assert.Equal(t, true, comparePath("filemac:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12", "filemac:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12")) 1726 | assert.Equal(t, true, comparePath("filemac:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB", "filemac:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12")) 1727 | assert.Equal(t, true, comparePath("filemac:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12", "filemac:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB")) 1728 | 1729 | assert.Equal(t, true, comparePath("filemac:/Macintosh HD/Library/FileMaker Server/Data/Databases/test/TestDB", "/Volumes/Macintosh HD/Library/FileMaker Server/Data/Databases/test/TestDB")) 1730 | assert.Equal(t, true, comparePath("filemac:/Macintosh HD/Library/FileMaker Server/Data/Databases/test/TestDB", "/Volumes/Macintosh HD/Library/FileMaker Server/Data/Databases/test/TestDB.fmp12")) 1731 | assert.Equal(t, true, comparePath("filemac:/Macintosh HD/Library/FileMaker Server/Data/Databases/test/TestDB.fmp12", "/Volumes/Macintosh HD/Library/FileMaker Server/Data/Databases/test/TestDB")) 1732 | assert.Equal(t, true, comparePath("filemac:/Macintosh HD/Library/FileMaker Server/Data/Databases/test/TestDB.fmp12", "/Volumes/Macintosh HD/Library/FileMaker Server/Data/Databases/test/TestDB.fmp12")) 1733 | 1734 | assert.Equal(t, true, comparePath("filewin:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB", "filewin:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB")) 1735 | assert.Equal(t, true, comparePath("filewin:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12", "filewin:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12")) 1736 | assert.Equal(t, true, comparePath("filewin:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB", "filewin:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12")) 1737 | assert.Equal(t, true, comparePath("filewin:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12", "filewin:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB")) 1738 | 1739 | assert.Equal(t, true, comparePath("/opt/FileMaker/FileMaker Server/Data/Databases/TestDB", "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB")) 1740 | assert.Equal(t, true, comparePath("/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12", "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12")) 1741 | assert.Equal(t, true, comparePath("/opt/FileMaker/FileMaker Server/Data/Databases/TestDB", "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12")) 1742 | assert.Equal(t, true, comparePath("/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12", "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB")) 1743 | 1744 | assert.Equal(t, true, comparePath("/opt/FileMaker/FileMaker Server/Data/Databases/TestDB", "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB")) 1745 | assert.Equal(t, true, comparePath("/opt/FileMaker/FileMaker Server/Data/Databases/TestDB", "filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12")) 1746 | assert.Equal(t, true, comparePath("filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12", "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB")) 1747 | assert.Equal(t, true, comparePath("filelinux:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12", "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12")) 1748 | 1749 | if runtime.GOOS == "darwin" { 1750 | assert.Equal(t, true, comparePath("/opt/FileMaker/FileMaker Server/Data/Databases/TestDB", "filemac:/"+getVolumeName()+"/opt/FileMaker/FileMaker Server/Data/Databases/TestDB")) 1751 | assert.Equal(t, true, comparePath("/opt/FileMaker/FileMaker Server/Data/Databases/TestDB", "filemac:/"+getVolumeName()+"/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12")) 1752 | assert.Equal(t, true, comparePath("filemac:/"+getVolumeName()+"/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12", "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB")) 1753 | assert.Equal(t, true, comparePath("filemac:/"+getVolumeName()+"/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12", "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12")) 1754 | } 1755 | 1756 | assert.Equal(t, true, comparePath("/opt/FileMaker/FileMaker Server/Data/Databases/TestDB", "filewin:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB")) 1757 | assert.Equal(t, true, comparePath("/opt/FileMaker/FileMaker Server/Data/Databases/TestDB", "filewin:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12")) 1758 | assert.Equal(t, true, comparePath("filewin:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12", "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB")) 1759 | assert.Equal(t, true, comparePath("filewin:/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12", "/opt/FileMaker/FileMaker Server/Data/Databases/TestDB.fmp12")) 1760 | } 1761 | 1762 | func TestGetErrorDescription(t *testing.T) { 1763 | assert.Equal(t, "", getErrorDescription(0)) 1764 | assert.Equal(t, "Unknown error", getErrorDescription(-1)) 1765 | assert.Equal(t, "Unavailable command", getErrorDescription(3)) 1766 | assert.Equal(t, "Command is unknown", getErrorDescription(4)) 1767 | assert.Equal(t, "Empty result", getErrorDescription(8)) 1768 | assert.Equal(t, "Access denied", getErrorDescription(9)) 1769 | assert.Equal(t, "Not Supported", getErrorDescription(21)) 1770 | assert.Equal(t, "Invalid user account and/or password; please try again", getErrorDescription(212)) 1771 | assert.Equal(t, "Unable to open the file", getErrorDescription(802)) 1772 | assert.Equal(t, "Parameter missing", getErrorDescription(958)) 1773 | assert.Equal(t, "Parameter is invalid", getErrorDescription(960)) 1774 | assert.Equal(t, "Parameter value is invalid", getErrorDescription(1708)) 1775 | assert.Equal(t, "Service already running", getErrorDescription(10006)) 1776 | assert.Equal(t, "Schedule at specified index does not exist", getErrorDescription(10600)) 1777 | assert.Equal(t, "Schedule is misconfigured; invalid taskType or run status", getErrorDescription(10601)) 1778 | assert.Equal(t, "Schedule can't be created or duplicated", getErrorDescription(10603)) 1779 | assert.Equal(t, "Cannot enable schedule", getErrorDescription(10604)) 1780 | assert.Equal(t, "No schedules created in configuration file", getErrorDescription(10610)) 1781 | assert.Equal(t, "Schedule name is already used", getErrorDescription(10611)) 1782 | assert.Equal(t, "No applicable files for this operation", getErrorDescription(10904)) 1783 | assert.Equal(t, "Script is missing", getErrorDescription(10906)) 1784 | assert.Equal(t, "System script aborted", getErrorDescription(10908)) 1785 | assert.Equal(t, "Invalid command", getErrorDescription(11000)) 1786 | assert.Equal(t, "Unable to create command", getErrorDescription(11002)) 1787 | assert.Equal(t, "Disconnect Client invalid ID", getErrorDescription(11005)) 1788 | assert.Equal(t, "File permission error", getErrorDescription(20402)) 1789 | assert.Equal(t, "File not found or not accessible.", getErrorDescription(20405)) 1790 | assert.Equal(t, "File already exists", getErrorDescription(20406)) 1791 | assert.Equal(t, "File read error", getErrorDescription(20408)) 1792 | assert.Equal(t, "SSL certificate expired", getErrorDescription(20630)) 1793 | assert.Equal(t, "SSL certificate verification error", getErrorDescription(20632)) 1794 | assert.Equal(t, "Parameters are invalid", getErrorDescription(25004)) 1795 | assert.Equal(t, "Invalid session error", getErrorDescription(25006)) 1796 | } 1797 | 1798 | func TestGetDateTimeStringOfCurrentTimeZone(t *testing.T) { 1799 | const location = "Asia/Tokyo" 1800 | loc, err := time.LoadLocation(location) 1801 | if err != nil { 1802 | loc = time.FixedZone(location, 9*60*60) 1803 | } 1804 | time.Local = loc 1805 | assert.Equal(t, "", getDateTimeStringOfCurrentTimeZone("", "2006/01/02 15:04:05", false)) 1806 | assert.Equal(t, "", getDateTimeStringOfCurrentTimeZone("0000-00-00 00:00:00", "2006/01/02 15:04:05", false)) 1807 | assert.Equal(t, "", getDateTimeStringOfCurrentTimeZone("0000-00-00 00:00:00 GMT", "2006/01/02 15:04:05", false)) 1808 | 1809 | //assert.Equal(t, "2006/01/03 00:04", getDateTimeStringOfCurrentTimeZone("2006-01-02T15:04:05")) 1810 | assert.Equal(t, "2006/01/02 15:04", getDateTimeStringOfCurrentTimeZone("2006-01-02T15:04:05", "2006/01/02 15:04", false)) 1811 | assert.Equal(t, "2006/01/03 00:04", getDateTimeStringOfCurrentTimeZone("2006-01-02T15:04:05", "2006/01/02 15:04", true)) 1812 | assert.Equal(t, "2006/01/02 15:04:05", getDateTimeStringOfCurrentTimeZone("2006-01-02T15:04:05", "2006/01/02 15:04:05", false)) 1813 | 1814 | //assert.Equal(t, "2006/01/03 00:04", getDateTimeStringOfCurrentTimeZone("2006-01-02 15:04:05 GMT")) 1815 | assert.Equal(t, "2006/01/02 15:04", getDateTimeStringOfCurrentTimeZone("2006-01-02 15:04:05 GMT", "2006/01/02 15:04", false)) 1816 | assert.Equal(t, "2006/01/03 00:04", getDateTimeStringOfCurrentTimeZone("2006-01-02 15:04:05 GMT", "2006/01/02 15:04", true)) 1817 | assert.Equal(t, "2006/01/02 15:04:05", getDateTimeStringOfCurrentTimeZone("2006-01-02 15:04:05 GMT", "2006/01/02 15:04:05", false)) 1818 | } 1819 | --------------------------------------------------------------------------------