]> Cypherpunks.ru repositories - nncp.git/blob - src/cmd/nncp-rm/main.go
Multicast areas
[nncp.git] / src / cmd / nncp-rm / main.go
1 /*
2 NNCP -- Node to Node copy, utilities for store-and-forward data exchange
3 Copyright (C) 2016-2021 Sergey Matveev <stargrave@stargrave.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, version 3 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 // Remove packet from the queue.
19 package main
20
21 import (
22         "flag"
23         "fmt"
24         "log"
25         "os"
26         "path/filepath"
27         "regexp"
28         "strconv"
29         "strings"
30         "time"
31
32         "go.cypherpunks.ru/nncp/v7"
33 )
34
35 func usage() {
36         fmt.Fprintf(os.Stderr, nncp.UsageHeader())
37         fmt.Fprintf(os.Stderr, "nncp-rm -- remove packet\n\n")
38         fmt.Fprintf(os.Stderr, "Usage: %s [options] -tmp\n", os.Args[0])
39         fmt.Fprintf(os.Stderr, "       %s [options] -lock\n", os.Args[0])
40         fmt.Fprintf(os.Stderr, "       %s [options] {-all|-node NODE} -part\n", os.Args[0])
41         fmt.Fprintf(os.Stderr, "       %s [options] {-all|-node NODE} -seen\n", os.Args[0])
42         fmt.Fprintf(os.Stderr, "       %s [options] {-all|-node NODE} -nock\n", os.Args[0])
43         fmt.Fprintf(os.Stderr, "       %s [options] {-all|-node NODE} -hdr\n", os.Args[0])
44         fmt.Fprintf(os.Stderr, "       %s [options] {-all|-node NODE} -area\n", os.Args[0])
45         fmt.Fprintf(os.Stderr, "       %s [options] {-all|-node NODE} {-rx|-tx}\n", os.Args[0])
46         fmt.Fprintf(os.Stderr, "       %s [options] {-all|-node NODE} -pkt PKT\n", os.Args[0])
47         fmt.Fprintln(os.Stderr, "-older option's time units are: (s)econds, (m)inutes, (h)ours, (d)ays")
48         fmt.Fprintln(os.Stderr, "Options:")
49         flag.PrintDefaults()
50 }
51
52 func main() {
53         var (
54                 cfgPath   = flag.String("cfg", nncp.DefaultCfgPath, "Path to configuration file")
55                 doAll     = flag.Bool("all", false, "Apply remove rules to all nodes")
56                 doTmp     = flag.Bool("tmp", false, "Remove all temporary files")
57                 doHdr     = flag.Bool("hdr", false, "Remove all .hdr files")
58                 doLock    = flag.Bool("lock", false, "Remove all lock files")
59                 nodeRaw   = flag.String("node", "", "Node to remove files in")
60                 doRx      = flag.Bool("rx", false, "Process received packets")
61                 doTx      = flag.Bool("tx", false, "Process transfered packets")
62                 doPart    = flag.Bool("part", false, "Remove only .part files")
63                 doSeen    = flag.Bool("seen", false, "Remove only .seen files")
64                 doNoCK    = flag.Bool("nock", false, "Remove only .nock files")
65                 doArea    = flag.Bool("area", false, "Remove only area/*.seen files")
66                 older     = flag.String("older", "", "XXX{smhd}: only older than XXX number of time units")
67                 dryRun    = flag.Bool("dryrun", false, "Do not actually remove files")
68                 pktRaw    = flag.String("pkt", "", "Packet to remove")
69                 spoolPath = flag.String("spool", "", "Override path to spool")
70                 quiet     = flag.Bool("quiet", false, "Print only errors")
71                 debug     = flag.Bool("debug", false, "Print debug messages")
72                 version   = flag.Bool("version", false, "Print version information")
73                 warranty  = flag.Bool("warranty", false, "Print warranty information")
74         )
75         log.SetFlags(log.Lshortfile)
76         flag.Usage = usage
77         flag.Parse()
78         if *warranty {
79                 fmt.Println(nncp.Warranty)
80                 return
81         }
82         if *version {
83                 fmt.Println(nncp.VersionGet())
84                 return
85         }
86
87         ctx, err := nncp.CtxFromCmdline(*cfgPath, *spoolPath, "", *quiet, false, false, *debug)
88         if err != nil {
89                 log.Fatalln("Error during initialization:", err)
90         }
91         ctx.Umask()
92
93         var oldBoundaryRaw int
94         if *older != "" {
95                 olderRe := regexp.MustCompile(`^(\d+)([smhd])$`)
96                 matches := olderRe.FindStringSubmatch(*older)
97                 if len(matches) != 1+2 {
98                         log.Fatalln("can not parse -older")
99                 }
100                 oldBoundaryRaw, err = strconv.Atoi(matches[1])
101                 if err != nil {
102                         log.Fatalln("can not parse -older:", err)
103                 }
104                 switch matches[2] {
105                 case "s":
106                         break
107                 case "m":
108                         oldBoundaryRaw *= 60
109                 case "h":
110                         oldBoundaryRaw *= 60 * 60
111                 case "d":
112                         oldBoundaryRaw *= 60 * 60 * 24
113                 }
114         }
115         oldBoundary := time.Second * time.Duration(oldBoundaryRaw)
116
117         now := time.Now()
118         if *doTmp {
119                 err = filepath.Walk(
120                         filepath.Join(ctx.Spool, "tmp"),
121                         func(path string, info os.FileInfo, err error) error {
122                                 if err != nil {
123                                         return err
124                                 }
125                                 if info.IsDir() {
126                                         return nil
127                                 }
128                                 if now.Sub(info.ModTime()) < oldBoundary {
129                                         ctx.LogD("rm-skip", nncp.LEs{{K: "File", V: path}}, func(les nncp.LEs) string {
130                                                 return fmt.Sprintf("File %s: too fresh, skipping", path)
131                                         })
132                                         return nil
133                                 }
134                                 ctx.LogI("rm", nncp.LEs{{K: "File", V: path}}, func(les nncp.LEs) string {
135                                         return fmt.Sprintf("File %s: removed", path)
136                                 })
137                                 if *dryRun {
138                                         return nil
139                                 }
140                                 return os.Remove(path)
141                         })
142                 if err != nil {
143                         log.Fatalln("Error during walking:", err)
144                 }
145                 return
146         }
147         if *doLock {
148                 err = filepath.Walk(ctx.Spool, func(path string, info os.FileInfo, err error) error {
149                         if err != nil {
150                                 return err
151                         }
152                         if info.IsDir() {
153                                 return nil
154                         }
155                         if strings.HasSuffix(info.Name(), ".lock") {
156                                 ctx.LogI("rm", nncp.LEs{{K: "File", V: path}}, func(les nncp.LEs) string {
157                                         return fmt.Sprintf("File %s: removed", path)
158                                 })
159                                 if *dryRun {
160                                         return nil
161                                 }
162                                 return os.Remove(path)
163                         }
164                         return nil
165                 })
166                 if err != nil {
167                         log.Fatalln("Error during walking:", err)
168                 }
169                 return
170         }
171         var nodeId *nncp.NodeId
172         if *nodeRaw == "" {
173                 if !*doAll {
174                         usage()
175                         os.Exit(1)
176                 }
177         } else {
178                 nodeId, err = nncp.NodeIdFromString(*nodeRaw)
179                 if err != nil {
180                         log.Fatalln("Invalid -node specified:", err)
181                 }
182         }
183         for _, node := range ctx.Neigh {
184                 if nodeId != nil && node.Id != nodeId {
185                         continue
186                 }
187                 remove := func(xx nncp.TRxTx) error {
188                         return filepath.Walk(
189                                 filepath.Join(ctx.Spool, node.Id.String(), string(xx)),
190                                 func(path string, info os.FileInfo, err error) error {
191                                         if err != nil {
192                                                 return err
193                                         }
194                                         if info.IsDir() {
195                                                 return nil
196                                         }
197                                         logMsg := func(les nncp.LEs) string {
198                                                 return fmt.Sprintf("File %s: removed", path)
199                                         }
200                                         if now.Sub(info.ModTime()) < oldBoundary {
201                                                 ctx.LogD("rm-skip", nncp.LEs{{K: "File", V: path}}, func(les nncp.LEs) string {
202                                                         return fmt.Sprintf("File %s: too fresh, skipping", path)
203                                                 })
204                                                 return nil
205                                         }
206                                         if (*doSeen && strings.HasSuffix(info.Name(), nncp.SeenSuffix)) ||
207                                                 (*doNoCK && strings.HasSuffix(info.Name(), nncp.NoCKSuffix)) ||
208                                                 (*doHdr && strings.HasSuffix(info.Name(), nncp.HdrSuffix)) ||
209                                                 (*doPart && strings.HasSuffix(info.Name(), nncp.PartSuffix)) {
210                                                 ctx.LogI("rm", nncp.LEs{{K: "File", V: path}}, logMsg)
211                                                 if *dryRun {
212                                                         return nil
213                                                 }
214                                                 return os.Remove(path)
215                                         }
216                                         if *pktRaw != "" && filepath.Base(info.Name()) == *pktRaw {
217                                                 ctx.LogI("rm", nncp.LEs{{K: "File", V: path}}, logMsg)
218                                                 if *dryRun {
219                                                         return nil
220                                                 }
221                                                 return os.Remove(path)
222                                         }
223                                         if !*doSeen && !*doNoCK && !*doHdr && !*doPart &&
224                                                 (*doRx || *doTx) &&
225                                                 ((*doRx && xx == nncp.TRx) || (*doTx && xx == nncp.TTx)) {
226                                                 ctx.LogI("rm", nncp.LEs{{K: "File", V: path}}, logMsg)
227                                                 if *dryRun {
228                                                         return nil
229                                                 }
230                                                 return os.Remove(path)
231                                         }
232                                         return nil
233                                 })
234                 }
235                 if *pktRaw != "" || *doRx || *doSeen || *doNoCK || *doHdr || *doPart {
236                         if err = remove(nncp.TRx); err != nil {
237                                 log.Fatalln("Can not remove:", err)
238                         }
239                 }
240                 if *pktRaw != "" || *doTx || *doHdr {
241                         if err = remove(nncp.TTx); err != nil {
242                                 log.Fatalln("Can not remove:", err)
243                         }
244                 }
245                 if *doArea {
246                         if err = filepath.Walk(
247                                 filepath.Join(ctx.Spool, node.Id.String(), nncp.AreaDir),
248                                 func(path string, info os.FileInfo, err error) error {
249                                         if err != nil {
250                                                 if os.IsNotExist(err) {
251                                                         return nil
252                                                 }
253                                                 return err
254                                         }
255                                         if info.IsDir() {
256                                                 return nil
257                                         }
258                                         if now.Sub(info.ModTime()) < oldBoundary {
259                                                 ctx.LogD("rm-skip", nncp.LEs{{K: "File", V: path}}, func(les nncp.LEs) string {
260                                                         return fmt.Sprintf("File %s: too fresh, skipping", path)
261                                                 })
262                                                 return nil
263                                         }
264                                         if strings.HasSuffix(info.Name(), nncp.SeenSuffix) {
265                                                 ctx.LogI(
266                                                         "rm",
267                                                         nncp.LEs{{K: "File", V: path}},
268                                                         func(les nncp.LEs) string {
269                                                                 return fmt.Sprintf("File %s: removed", path)
270                                                         },
271                                                 )
272                                                 if *dryRun {
273                                                         return nil
274                                                 }
275                                                 return os.Remove(path)
276                                         }
277                                         return nil
278                                 }); err != nil {
279                                 log.Fatalln("Can not remove:", err)
280                         }
281                 }
282         }
283 }