From 33938ee364a42d907fd2b59acb5b7dc1c086df93 Mon Sep 17 00:00:00 2001 From: jpappa200 Date: Thu, 2 Jun 2022 11:53:49 -0400 Subject: [PATCH 01/13] Added option for uid and gid values and checks --- cache-config/t3c-diff/t3c-diff.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cache-config/t3c-diff/t3c-diff.go b/cache-config/t3c-diff/t3c-diff.go index e6f6f5ae59..58c747737d 100644 --- a/cache-config/t3c-diff/t3c-diff.go +++ b/cache-config/t3c-diff/t3c-diff.go @@ -49,6 +49,8 @@ func main() { version := getopt.BoolLong("version", 'V', "Print version information and exit") lineComment := getopt.StringLong("line_comment", 'l', "#", "Comment symbol") mode := getopt.IntLong("file-mode", 'm', 0644, "file mode default is 644") + uid := getopt.IntLong("file-uid", 'u', 0, "file uid default is 0") + gid := getopt.IntLong("file-gid", 'g', 0, "file gid default is 0") fa := getopt.StringLong("file-a", 'a', "", "first diff file") fb := getopt.StringLong("file-b", 'b', "", "second diff file") getopt.ParseV2() @@ -116,18 +118,26 @@ func main() { log.Infoln("File permissions are incorrect, should be ", fmt.Sprintf("%#o", *mode)) os.Exit(1) } + if t3cutil.OwnershipCk(fileNameA, *uid, *gid) { + log.Infoln("user or group ownership are incorrect, should be ", fmt.Sprintf("Uid:%d Gid:%d", *uid, *gid)) + os.Exit(1) + } case fileNameB != "stdin": if t3cutil.PermCk(fileNameB, *mode) { log.Infoln("File permissions are incorrect, should be ", fmt.Sprintf("%#o", *mode)) os.Exit(1) } + if t3cutil.OwnershipCk(fileNameB, *uid, *gid) { + log.Infoln("user or group ownership are incorrect, should be ", fmt.Sprintf("Uid:%d Gid:%d", *uid, *gid)) + os.Exit(1) + } } os.Exit(0) } const usageStr = `usage: t3c-diff [--help] - -a -b -l -m + -a -b -l -m -u -g Either file may be 'stdin', in which case that file is read from stdin. Either file may not exist. From 05d2c94505df452b50a0b20e49276631e39d603a Mon Sep 17 00:00:00 2001 From: jpappa200 Date: Thu, 2 Jun 2022 11:54:58 -0400 Subject: [PATCH 02/13] added uid/gid to command and diff func --- cache-config/t3c-apply/torequest/cmd.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cache-config/t3c-apply/torequest/cmd.go b/cache-config/t3c-apply/torequest/cmd.go index 74b80da0b2..fcf347e634 100644 --- a/cache-config/t3c-apply/torequest/cmd.go +++ b/cache-config/t3c-apply/torequest/cmd.go @@ -277,12 +277,14 @@ func sendUpdate(cfg config.Cfg, configApplyTime, revalApplyTime *time.Time, conf // diff calls t3c-diff to diff the given new file and the file on disk. Returns whether they're different. // Logs the difference. // If the file on disk doesn't exist, returns true and logs the entire file as a diff. -func diff(cfg config.Cfg, newFile []byte, fileLocation string, reportOnly bool, perm os.FileMode) (bool, error) { +func diff(cfg config.Cfg, newFile []byte, fileLocation string, reportOnly bool, perm os.FileMode, uid int, gid int) (bool, error) { diffMsg := "" args := []string{ "--file-a=stdin", "--file-b=" + fileLocation, "--file-mode=" + fmt.Sprintf("%#o", perm), + "--file-uid=" + fmt.Sprint(uid), + "--file-gid=" + fmt.Sprint(gid), } stdOut, stdErr, code := t3cutil.DoInput(newFile, `t3c-diff`, args...) From e4b8eec8fb7c5f9831b7e806dcaa7995986bc504 Mon Sep 17 00:00:00 2001 From: jpappa200 Date: Thu, 2 Jun 2022 11:57:44 -0400 Subject: [PATCH 03/13] added gid/uid to diff func --- cache-config/t3c-apply/torequest/torequest.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cache-config/t3c-apply/torequest/torequest.go b/cache-config/t3c-apply/torequest/torequest.go index 7a107d7c9b..e61168209e 100644 --- a/cache-config/t3c-apply/torequest/torequest.go +++ b/cache-config/t3c-apply/torequest/torequest.go @@ -237,7 +237,7 @@ func (r *TrafficOpsReq) checkConfigFile(cfg *ConfigFile, filesAdding []string) e } } - changeNeeded, err := diff(r.Cfg, cfg.Body, cfg.Path, r.Cfg.ReportOnly, cfg.Perm) + changeNeeded, err := diff(r.Cfg, cfg.Body, cfg.Path, r.Cfg.ReportOnly, cfg.Perm, cfg.Uid, cfg.Gid) if err != nil { return errors.New("getting diff: " + err.Error()) From 72a48f1a71c581a78bf59bb0b4bfa96fcfe91139 Mon Sep 17 00:00:00 2001 From: jpappa200 Date: Thu, 2 Jun 2022 11:58:43 -0400 Subject: [PATCH 04/13] added func for ownership check --- cache-config/t3c-tail/t3c-tail.go | 125 ++++++++++++++++++++++++++++++ cache-config/t3cutil/t3cutil.go | 14 ++++ 2 files changed, 139 insertions(+) create mode 100644 cache-config/t3c-tail/t3c-tail.go diff --git a/cache-config/t3c-tail/t3c-tail.go b/cache-config/t3c-tail/t3c-tail.go new file mode 100644 index 0000000000..d75db7f4ca --- /dev/null +++ b/cache-config/t3c-tail/t3c-tail.go @@ -0,0 +1,125 @@ +package main + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import ( + "encoding/json" + "fmt" + "os" + "regexp" + "time" + + "github.com/apache/trafficcontrol/cache-config/t3cutil" + "github.com/nxadm/tail" + "github.com/pborman/getopt/v2" +) + + const AppName = "t3c-tail" + + // Version is the application version. +// This is overwritten by the build with the current project version. +var Version = "0.4" + +// GitRevision is the git revision the application was built from. +// This is overwritten by the build with the current project version. +var GitRevision = "nogit" + +//default time out is 15 seconds, if not included in json input. +var timeOutSeconds = 15 + + + + func main() { + version := getopt.BoolLong("version", 'V', "Print version information and exit.") + help := getopt.BoolLong("help", 'h', "Print usage information and exit") + getopt.Parse() + + if *help { + fmt.Println(usageStr()) + os.Exit(0) + } else if *version { + fmt.Println(t3cutil.VersionStr(AppName, Version, GitRevision)) + os.Exit(0) + } + + tailCfg := &TailCfg{} + if err := json.NewDecoder(os.Stdin).Decode(tailCfg); err != nil { + fmt.Println("Error reading json input", err) + } + + if tailCfg.Match == nil { + fmt.Println("must provide a regex to match") + fmt.Println(usageStr()) + os.Exit(1) + } + + logMatch := regexp.MustCompile(*tailCfg.Match) + timeOut := timeOutSeconds + if tailCfg.TimeOut != nil { + timeOut = *tailCfg.TimeOut + } + + file := tailCfg.File + t, err := tail.TailFile(*file, + tail.Config { + MustExist: true, + Follow: true , + Location: &tail.SeekInfo { + Offset: 0, + Whence: 2, + }, + }) + if err != nil { + fmt.Println("error running tail on ", file) + os.Exit(1) + } + go func() { + for line := range t.Lines { + if logMatch.MatchString(line.Text) { + fmt.Println(line.Text) + } + } + }() + + time.Sleep(time.Second * time.Duration(timeOut)) + fmt.Println("stopping") + err = t.Stop() + if err != nil { + fmt.Printf("ERROR: %s\n", err) + } + t.Cleanup() + +} + +type TailCfg struct { + File *string `json:"file"` + Match *string `json:"match"` + TimeOut *int `json:"timeOut"` +} + +func usageStr() string { + return `usage: t3c-tail [--help] + accepts json input from stdin in the following format: + file is file you want to tail + match is regex string you wish to match on, if you want everything use '.*' + timeOut is given in seconds the default is 15 + {"file":"diags.log", "serviceNeeds":"restart", "timeOut": 4} + ` +} \ No newline at end of file diff --git a/cache-config/t3cutil/t3cutil.go b/cache-config/t3cutil/t3cutil.go index 5678ba9c3f..a81966d199 100644 --- a/cache-config/t3cutil/t3cutil.go +++ b/cache-config/t3cutil/t3cutil.go @@ -30,6 +30,7 @@ import ( "os/exec" "regexp" "strings" + "syscall" ) type ATSConfigFile struct { @@ -86,6 +87,19 @@ func PermCk(path string, perm int) bool { return false } +// OwnershipCk will compare owner and group settings against existing file and owner/group settings provided. +func OwnershipCk(path string, uid int, gid int) bool { + file, err := os.Stat(path) + if err != nil { + fmt.Println("error getting file status") + } + stat := file.Sys().(*syscall.Stat_t) + if uid != int(stat.Uid) || gid != int(stat.Gid) { + return true + } + return false +} + // NewLineFilter removes carriage returns // from config files while making comparisons. func NewLineFilter(str string) string { From 0ad50eecbbd94f5d111989a675866b706775e733 Mon Sep 17 00:00:00 2001 From: jpappa200 Date: Thu, 2 Jun 2022 12:46:50 -0400 Subject: [PATCH 05/13] added change log entry for t3c diff --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67bdef8de6..dd9be2d21d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Added a Traffic Ops endpoint and Traffic Portal page to view all CDNi configuration update requests and approve or deny. - Added layered profile feature to 4.0 for `GET` /deliveryservices/{id}/servers/ and /deliveryservices/{id}/servers/eligible. - Change to t3c regex_revalidate so that STALE is no longer explicitly added for default revalidate rule for ATS version backwards compatibility. +- Change to t3c diff to flag a config file for replacement if owner/group settings are not `ats` [#6879](https://github.com/apache/trafficcontrol/issues/6879). ### Fixed - [#6291](https://github.com/apache/trafficcontrol/issues/6291) Prevent Traffic Ops from modifying and/or deleting reserved statuses. From e14be95cf86c7a518c7e3673f2d5d206a5b4e762 Mon Sep 17 00:00:00 2001 From: Joe Pappano Date: Thu, 2 Jun 2022 12:59:29 -0400 Subject: [PATCH 06/13] should not be part of this branch --- cache-config/t3c-tail/t3c-tail.go | 125 ------------------------------ 1 file changed, 125 deletions(-) delete mode 100644 cache-config/t3c-tail/t3c-tail.go diff --git a/cache-config/t3c-tail/t3c-tail.go b/cache-config/t3c-tail/t3c-tail.go deleted file mode 100644 index d75db7f4ca..0000000000 --- a/cache-config/t3c-tail/t3c-tail.go +++ /dev/null @@ -1,125 +0,0 @@ -package main - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import ( - "encoding/json" - "fmt" - "os" - "regexp" - "time" - - "github.com/apache/trafficcontrol/cache-config/t3cutil" - "github.com/nxadm/tail" - "github.com/pborman/getopt/v2" -) - - const AppName = "t3c-tail" - - // Version is the application version. -// This is overwritten by the build with the current project version. -var Version = "0.4" - -// GitRevision is the git revision the application was built from. -// This is overwritten by the build with the current project version. -var GitRevision = "nogit" - -//default time out is 15 seconds, if not included in json input. -var timeOutSeconds = 15 - - - - func main() { - version := getopt.BoolLong("version", 'V', "Print version information and exit.") - help := getopt.BoolLong("help", 'h', "Print usage information and exit") - getopt.Parse() - - if *help { - fmt.Println(usageStr()) - os.Exit(0) - } else if *version { - fmt.Println(t3cutil.VersionStr(AppName, Version, GitRevision)) - os.Exit(0) - } - - tailCfg := &TailCfg{} - if err := json.NewDecoder(os.Stdin).Decode(tailCfg); err != nil { - fmt.Println("Error reading json input", err) - } - - if tailCfg.Match == nil { - fmt.Println("must provide a regex to match") - fmt.Println(usageStr()) - os.Exit(1) - } - - logMatch := regexp.MustCompile(*tailCfg.Match) - timeOut := timeOutSeconds - if tailCfg.TimeOut != nil { - timeOut = *tailCfg.TimeOut - } - - file := tailCfg.File - t, err := tail.TailFile(*file, - tail.Config { - MustExist: true, - Follow: true , - Location: &tail.SeekInfo { - Offset: 0, - Whence: 2, - }, - }) - if err != nil { - fmt.Println("error running tail on ", file) - os.Exit(1) - } - go func() { - for line := range t.Lines { - if logMatch.MatchString(line.Text) { - fmt.Println(line.Text) - } - } - }() - - time.Sleep(time.Second * time.Duration(timeOut)) - fmt.Println("stopping") - err = t.Stop() - if err != nil { - fmt.Printf("ERROR: %s\n", err) - } - t.Cleanup() - -} - -type TailCfg struct { - File *string `json:"file"` - Match *string `json:"match"` - TimeOut *int `json:"timeOut"` -} - -func usageStr() string { - return `usage: t3c-tail [--help] - accepts json input from stdin in the following format: - file is file you want to tail - match is regex string you wish to match on, if you want everything use '.*' - timeOut is given in seconds the default is 15 - {"file":"diags.log", "serviceNeeds":"restart", "timeOut": 4} - ` -} \ No newline at end of file From 77c645f87dec406bd26253fdaec8e8f432ce2c68 Mon Sep 17 00:00:00 2001 From: jpappa200 Date: Thu, 2 Jun 2022 13:06:29 -0400 Subject: [PATCH 07/13] added uid and gid to usage string --- cache-config/t3c-diff/t3c-diff.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cache-config/t3c-diff/t3c-diff.go b/cache-config/t3c-diff/t3c-diff.go index 58c747737d..dd0a2bafcd 100644 --- a/cache-config/t3c-diff/t3c-diff.go +++ b/cache-config/t3c-diff/t3c-diff.go @@ -148,6 +148,9 @@ If one file exists but the other doesn't, it will always be a diff. Mode is file permissions in octal format, default is 0644. Line comment is a character that signals the line is a comment, default is # +Uid is the user id of the file's owner, default is 0. +Gid is the id of the group the file is a member of, default is 0. + Note this means there may be no diff text printed to stdout but still exit 1 indicating a diff if the file being created or deleted is semantically empty.` From 6fb1acda20a3ceaf91cd7ce5cc44313b3213a7a4 Mon Sep 17 00:00:00 2001 From: jpappa200 Date: Thu, 2 Jun 2022 13:29:38 -0400 Subject: [PATCH 08/13] fixed typo --- cache-config/t3cutil/t3cutil.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cache-config/t3cutil/t3cutil.go b/cache-config/t3cutil/t3cutil.go index a81966d199..67d20bceea 100644 --- a/cache-config/t3cutil/t3cutil.go +++ b/cache-config/t3cutil/t3cutil.go @@ -91,7 +91,7 @@ func PermCk(path string, perm int) bool { func OwnershipCk(path string, uid int, gid int) bool { file, err := os.Stat(path) if err != nil { - fmt.Println("error getting file status") + fmt.Println("error getting file status", path) } stat := file.Sys().(*syscall.Stat_t) if uid != int(stat.Uid) || gid != int(stat.Gid) { From 2cdcbf680a48be1a95ab5dac7a36957960705d3c Mon Sep 17 00:00:00 2001 From: jpappa200 Date: Thu, 2 Jun 2022 13:36:11 -0400 Subject: [PATCH 09/13] fixed formatting error --- cache-config/t3cutil/t3cutil.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cache-config/t3cutil/t3cutil.go b/cache-config/t3cutil/t3cutil.go index 67d20bceea..782548301f 100644 --- a/cache-config/t3cutil/t3cutil.go +++ b/cache-config/t3cutil/t3cutil.go @@ -91,7 +91,7 @@ func PermCk(path string, perm int) bool { func OwnershipCk(path string, uid int, gid int) bool { file, err := os.Stat(path) if err != nil { - fmt.Println("error getting file status", path) + fmt.Println("error getting file status", path) } stat := file.Sys().(*syscall.Stat_t) if uid != int(stat.Uid) || gid != int(stat.Gid) { From 33a32d5efe9a577916a6bdf017186473864742f2 Mon Sep 17 00:00:00 2001 From: jpappa200 Date: Mon, 6 Jun 2022 13:44:36 -0400 Subject: [PATCH 10/13] added missing variables and flags --- cache-config/t3c-diff/README.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/cache-config/t3c-diff/README.md b/cache-config/t3c-diff/README.md index 00eec199cf..21a957faa1 100644 --- a/cache-config/t3c-diff/README.md +++ b/cache-config/t3c-diff/README.md @@ -38,7 +38,7 @@ t3c-diff - Traffic Control Cache Configuration contextual diff tool # SYNOPSIS -t3c-diff \ \ +t3c-diff \-a \ \- b \ \-l \ \-m \ \-u \ \-g \ [\-\-help] @@ -58,12 +58,37 @@ If one file exists but the other doesn't, it will always be a diff. Note this means there may be no diff text printed to stdout but still exit 1 indicating a diff if the file being created or deleted is semantically empty. +Mode is file permissions in octal format, default is 0644. +Line comment is a character that signals the line is a comment, default is # + +Uid is the user id of the file's owner, default is running process's uid. +Gid is the id of the group the file is a member of, default running process's gid.` + # OPTIONS +-a, -\-file-a + + Path to first diff file, can also be stdin. + +-b, -\-file-b + Path to second diff file, can also be stdin. + +-g, -\-file-gid + Group id the file being checked should have. + -h, -\-help Print usage info and exit. +-l, -\-line_comment + Symbol used to denote the line is a comment. + +-m, -\-file-mode + Octal permissions mode for file being checked. + +-u, -\-file-uid + User id the file being checked should have. + -V, -\-version Print version information and exit. From ee7664087d263d38cc85c85422974831b8329a7c Mon Sep 17 00:00:00 2001 From: jpappa200 Date: Mon, 6 Jun 2022 13:46:17 -0400 Subject: [PATCH 11/13] running process's uid/gid will be used by defalut --- cache-config/t3c-diff/t3c-diff.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cache-config/t3c-diff/t3c-diff.go b/cache-config/t3c-diff/t3c-diff.go index dd0a2bafcd..2bd487950c 100644 --- a/cache-config/t3c-diff/t3c-diff.go +++ b/cache-config/t3c-diff/t3c-diff.go @@ -78,6 +78,14 @@ func main() { os.Exit(4) } + if *uid == 0 { + *uid = os.Geteuid() + } + + if *gid == 0 { + *gid = os.Getgid() + } + fileA, fileAExisted, err := readFileOrStdin(fileNameA) if err != nil { log.Errorf("error reading first: %s\n", err.Error()) From 8e98ca60b98e97188ab40513f3400696a7c3257f Mon Sep 17 00:00:00 2001 From: jpappa200 Date: Mon, 6 Jun 2022 14:09:40 -0400 Subject: [PATCH 12/13] fixed formatting error. --- cache-config/t3c-diff/t3c-diff.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cache-config/t3c-diff/t3c-diff.go b/cache-config/t3c-diff/t3c-diff.go index 2bd487950c..4c5eefc379 100644 --- a/cache-config/t3c-diff/t3c-diff.go +++ b/cache-config/t3c-diff/t3c-diff.go @@ -81,7 +81,7 @@ func main() { if *uid == 0 { *uid = os.Geteuid() } - + if *gid == 0 { *gid = os.Getgid() } From ebd7ada0984bb5f79eea98e2fdac7d469514a21e Mon Sep 17 00:00:00 2001 From: jpappa200 Date: Wed, 8 Jun 2022 14:35:27 -0400 Subject: [PATCH 13/13] made changes to the help text and removed extraneous space --- cache-config/t3c-diff/README.md | 6 +++--- cache-config/t3c-diff/t3c-diff.go | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cache-config/t3c-diff/README.md b/cache-config/t3c-diff/README.md index 21a957faa1..fd3e945cf7 100644 --- a/cache-config/t3c-diff/README.md +++ b/cache-config/t3c-diff/README.md @@ -38,7 +38,7 @@ t3c-diff - Traffic Control Cache Configuration contextual diff tool # SYNOPSIS -t3c-diff \-a \ \- b \ \-l \ \-m \ \-u \ \-g \ +t3c-diff \-a \ \-b \ \-l \ \-m \ \-u \ \-g \ [\-\-help] @@ -61,8 +61,8 @@ if the file being created or deleted is semantically empty. Mode is file permissions in octal format, default is 0644. Line comment is a character that signals the line is a comment, default is # -Uid is the user id of the file's owner, default is running process's uid. -Gid is the id of the group the file is a member of, default running process's gid.` +Uid is the User id the file being checked should have, default is running process's uid. +Gid is the Group id the file being checked should have, default is running process's gid.` # OPTIONS diff --git a/cache-config/t3c-diff/t3c-diff.go b/cache-config/t3c-diff/t3c-diff.go index 4c5eefc379..e80eb39a4b 100644 --- a/cache-config/t3c-diff/t3c-diff.go +++ b/cache-config/t3c-diff/t3c-diff.go @@ -49,8 +49,8 @@ func main() { version := getopt.BoolLong("version", 'V', "Print version information and exit") lineComment := getopt.StringLong("line_comment", 'l', "#", "Comment symbol") mode := getopt.IntLong("file-mode", 'm', 0644, "file mode default is 644") - uid := getopt.IntLong("file-uid", 'u', 0, "file uid default is 0") - gid := getopt.IntLong("file-gid", 'g', 0, "file gid default is 0") + uid := getopt.IntLong("file-uid", 'u', 0, "User id the file being checked should have, default is running process's uid") + gid := getopt.IntLong("file-gid", 'g', 0, "Group id the file being checked should have, default is running process's gid") fa := getopt.StringLong("file-a", 'a', "", "first diff file") fb := getopt.StringLong("file-b", 'b', "", "second diff file") getopt.ParseV2() @@ -156,8 +156,8 @@ If one file exists but the other doesn't, it will always be a diff. Mode is file permissions in octal format, default is 0644. Line comment is a character that signals the line is a comment, default is # -Uid is the user id of the file's owner, default is 0. -Gid is the id of the group the file is a member of, default is 0. +Uid is the User id the file being checked should have, default is running process's uid. +Gid is the Group id the file being checked should have, default is running process's gid. Note this means there may be no diff text printed to stdout but still exit 1 indicating a diff if the file being created or deleted is semantically empty.`