]> Cypherpunks.ru repositories - nncp.git/blob - src/cmd/nncp-rm/main.go
b9ca28977c7380834393c7709cc585a9e95a1238
[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                 node, err := ctx.FindNode(*nodeRaw)
179                 if err != nil {
180                         log.Fatalln("Invalid -node specified:", err)
181                 }
182                 nodeId = node.Id
183         }
184         for _, node := range ctx.Neigh {
185                 if nodeId != nil && node.Id != nodeId {
186                         continue
187                 }
188                 remove := func(xx nncp.TRxTx) error {
189                         return filepath.Walk(
190                                 filepath.Join(ctx.Spool, node.Id.String(), string(xx)),
191                                 func(path string, info os.FileInfo, err error) error {
192                                         if err != nil {
193                                                 return err
194                                         }
195                                         if info.IsDir() {
196                                                 return nil
197                                         }
198                                         logMsg := func(les nncp.LEs) string {
199                                                 return fmt.Sprintf("File %s: removed", path)
200                                         }
201                                         if now.Sub(info.ModTime()) < oldBoundary {
202                                                 ctx.LogD("rm-skip", nncp.LEs{{K: "File", V: path}}, func(les nncp.LEs) string {
203                                                         return fmt.Sprintf("File %s: too fresh, skipping", path)
204                                                 })
205                                                 return nil
206                                         }
207                                         if (*doNoCK && strings.HasSuffix(info.Name(), nncp.NoCKSuffix)) ||
208                                                 (*doPart && strings.HasSuffix(info.Name(), nncp.PartSuffix)) {
209                                                 ctx.LogI("rm", nncp.LEs{{K: "File", V: path}}, logMsg)
210                                                 if *dryRun {
211                                                         return nil
212                                                 }
213                                                 return os.Remove(path)
214                                         }
215                                         if *pktRaw != "" && filepath.Base(info.Name()) == *pktRaw {
216                                                 ctx.LogI("rm", nncp.LEs{{K: "File", V: path}}, logMsg)
217                                                 if *dryRun {
218                                                         return nil
219                                                 }
220                                                 return os.Remove(path)
221                                         }
222                                         if !*doSeen && !*doNoCK && !*doHdr && !*doPart &&
223                                                 (*doRx || *doTx) &&
224                                                 ((*doRx && xx == nncp.TRx) || (*doTx && xx == nncp.TTx)) {
225                                                 ctx.LogI("rm", nncp.LEs{{K: "File", V: path}}, logMsg)
226                                                 if *dryRun {
227                                                         return nil
228                                                 }
229                                                 return os.Remove(path)
230                                         }
231                                         return nil
232                                 })
233                 }
234                 if *pktRaw != "" || *doRx || *doNoCK || *doPart {
235                         if err = remove(nncp.TRx); err != nil {
236                                 log.Fatalln("Can not remove:", err)
237                         }
238                 }
239                 if *pktRaw != "" || *doTx || *doHdr {
240                         if err = remove(nncp.TTx); err != nil {
241                                 log.Fatalln("Can not remove:", err)
242                         }
243                 }
244                 removeSub := func(p string, everything bool) error {
245                         return filepath.Walk(
246                                 p, func(path string, info os.FileInfo, err error) error {
247                                         if err != nil {
248                                                 if os.IsNotExist(err) {
249                                                         return nil
250                                                 }
251                                                 return err
252                                         }
253                                         if info.IsDir() {
254                                                 return nil
255                                         }
256                                         logMsg := func(les nncp.LEs) string {
257                                                 return fmt.Sprintf("File %s: removed", path)
258                                         }
259                                         if everything {
260                                                 ctx.LogI("rm", nncp.LEs{{K: "File", V: path}}, logMsg)
261                                                 if *dryRun {
262                                                         return nil
263                                                 }
264                                                 return os.Remove(path)
265                                         }
266                                         if now.Sub(info.ModTime()) < oldBoundary {
267                                                 ctx.LogD(
268                                                         "rm-skip", nncp.LEs{{K: "File", V: path}},
269                                                         func(les nncp.LEs) string {
270                                                                 return fmt.Sprintf("File %s: too fresh, skipping", path)
271                                                         },
272                                                 )
273                                         } else if !*dryRun {
274                                                 return os.Remove(path)
275                                         }
276                                         return nil
277                                 },
278                         )
279                 }
280                 if *doRx || *doSeen {
281                         if err = removeSub(filepath.Join(
282                                 ctx.Spool, node.Id.String(), string(nncp.TRx), nncp.SeenDir,
283                         ), *doSeen); err != nil {
284                                 log.Fatalln("Can not remove:", err)
285                         }
286                 }
287                 if *doRx || *doHdr {
288                         if err = removeSub(filepath.Join(
289                                 ctx.Spool, node.Id.String(), string(nncp.TRx), nncp.HdrDir,
290                         ), *doHdr); err != nil {
291                                 log.Fatalln("Can not remove:", err)
292                         }
293                 }
294                 if *doTx || *doHdr {
295                         if err = removeSub(filepath.Join(
296                                 ctx.Spool, node.Id.String(), string(nncp.TTx), nncp.HdrDir,
297                         ), *doHdr); err != nil {
298                                 log.Fatalln("Can not remove:", err)
299                         }
300                 }
301                 if *doArea {
302                         if err = filepath.Walk(
303                                 filepath.Join(ctx.Spool, node.Id.String(), nncp.AreaDir),
304                                 func(path string, info os.FileInfo, err error) error {
305                                         if err != nil {
306                                                 if os.IsNotExist(err) {
307                                                         return nil
308                                                 }
309                                                 return err
310                                         }
311                                         if info.IsDir() {
312                                                 return nil
313                                         }
314                                         if now.Sub(info.ModTime()) < oldBoundary {
315                                                 ctx.LogD("rm-skip", nncp.LEs{{K: "File", V: path}}, func(les nncp.LEs) string {
316                                                         return fmt.Sprintf("File %s: too fresh, skipping", path)
317                                                 })
318                                                 return nil
319                                         }
320                                         ctx.LogI(
321                                                 "rm",
322                                                 nncp.LEs{{K: "File", V: path}},
323                                                 func(les nncp.LEs) string {
324                                                         return fmt.Sprintf("File %s: removed", path)
325                                                 },
326                                         )
327                                         if *dryRun {
328                                                 return nil
329                                         }
330                                         return os.Remove(path)
331                                 }); err != nil {
332                                 log.Fatalln("Can not remove:", err)
333                         }
334                 }
335         }
336 }