c0de85cea5d4eac826e567a4b0968e5ba28e71cd
[samba.git] / source / utils / smbcontrol.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Send messages to other Samba daemons
5
6    Copyright (C) Tim Potter 2003
7    Copyright (C) Andrew Tridgell 1994-1998
8    Copyright (C) Martin Pool 2001-2002
9    Copyright (C) Simo Sorce 2002
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26 #include "includes.h"
27
28 /* Default timeout value when waiting for replies (in seconds) */
29
30 #define DEFAULT_TIMEOUT 10
31
32 static int timeout = DEFAULT_TIMEOUT;
33 static int num_replies;         /* Used by message callback fns */
34
35 /* Send a message to a destination pid.  Zero means broadcast smbd. */
36
37 static BOOL send_message(pid_t pid, int msg_type, const void *buf, int len,
38                          BOOL duplicates)
39 {
40         TDB_CONTEXT *tdb;
41         BOOL ret;
42         int n_sent = 0;
43
44         if (!message_init())
45                 return False;
46
47         if (pid != 0)
48                 return message_send_pid(pid, msg_type, buf, len, duplicates);
49
50         tdb = tdb_open_log(lock_path("connections.tdb"), 0, 
51                            TDB_DEFAULT, O_RDWR, 0);
52         if (!tdb) {
53                 fprintf(stderr,"Failed to open connections database"
54                         ": %s\n", strerror(errno));
55                 return False;
56         }
57         
58         ret = message_send_all(tdb,msg_type, buf, len, duplicates,
59                                &n_sent);
60         DEBUG(10,("smbcontrol/send_message: broadcast message to "
61                   "%d processes\n", n_sent));
62         
63         tdb_close(tdb);
64         
65         return ret;
66 }
67
68 /* Wait for one or more reply messages */
69
70 static void wait_replies(BOOL multiple_replies)
71 {
72         time_t start_time = time(NULL);
73
74         /* Wait around a bit.  This is pretty disgusting - we have to
75            busy-wait here as there is no nicer way to do it. */
76
77         do {
78                 message_dispatch();
79                 if (num_replies > 0 && !multiple_replies)
80                         break;
81                 sleep(1);
82         } while (timeout - (time(NULL) - start_time) > 0);
83 }
84
85 /* Message handler callback that displays the PID and a string on stdout */
86
87 static void print_pid_string_cb(int msg_type, pid_t pid, void *buf, size_t len)
88 {
89         printf("PID %u: %.*s", (unsigned int)pid, (int)len, (const char *)buf);
90         num_replies++;
91 }
92
93 /* Message handler callback that displays a string on stdout */
94
95 static void print_string_cb(int msg_type, pid_t pid, void *buf, size_t len)
96 {
97         printf("%.*s", (int)len, (const char *)buf);
98         num_replies++;
99 }
100
101 /* Send no message.  Useful for testing. */
102
103 static BOOL do_noop(const pid_t pid, const int argc, const char **argv)
104 {
105         if (argc != 1) {
106                 fprintf(stderr, "Usage: smbcontrol <dest> noop\n");
107                 return False;
108         }
109
110         /* Move along, nothing to see here */
111
112         return True;
113 }
114
115 /* Send a debug string */
116
117 static BOOL do_debug(const pid_t pid, const int argc, const char **argv)
118 {
119         if (argc != 2) {
120                 fprintf(stderr, "Usage: smbcontrol <dest> debug "
121                         "<debug-string>\n");
122                 return False;
123         }
124
125         return send_message(
126                 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
127 }
128
129 /* Force a browser election */
130
131 static BOOL do_election(const pid_t pid, const int argc, const char **argv)
132 {
133         if (argc != 1) {
134                 fprintf(stderr, "Usage: smbcontrol <dest> force-election\n");
135                 return False;
136         }
137
138         return send_message(
139                 pid, MSG_FORCE_ELECTION, NULL, 0, False);
140 }
141
142 /* Ping a samba daemon process */
143
144 static void pong_cb(int msg_type, pid_t pid, void *buf, size_t len)
145 {
146         printf("PONG from pid %u\n", (unsigned int)pid);
147         num_replies++;
148 }
149
150 static BOOL do_ping(const pid_t pid, const int argc, const char **argv)
151 {
152         if (argc != 1) {
153                 fprintf(stderr, "Usage: smbcontrol <dest> ping\n");
154                 return False;
155         }
156
157         /* Send a message and register our interest in a reply */
158
159         if (!send_message(pid, MSG_PING, NULL, 0, False))
160                 return False;
161
162         message_register(MSG_PONG, pong_cb);
163
164         wait_replies(pid == 0);
165
166         /* No replies were received within the timeout period */
167
168         if (num_replies == 0)
169                 printf("No replies received\n");
170
171         message_deregister(MSG_PONG);
172
173         return num_replies;
174 }
175
176 /* Set profiling options */
177
178 static BOOL do_profile(const pid_t pid, const int argc, const char **argv)
179 {
180         int v;
181
182         if (argc != 2) {
183                 fprintf(stderr, "Usage: smbcontrol <dest> profile "
184                         "<off|count|on|flush>\n");
185                 return False;
186         }
187
188         if (strcmp(argv[1], "off") == 0) {
189                 v = 0;
190         } else if (strcmp(argv[1], "count") == 0) {
191                 v = 1;
192         } else if (strcmp(argv[1], "on") == 0) {
193                 v = 2;
194         } else if (strcmp(argv[1], "flush") == 0) {
195                 v = 3;
196         } else {
197                 fprintf(stderr, "Unknown profile command '%s'\n", argv[1]);
198                 return False;
199         }
200
201         return send_message(pid, MSG_PROFILE, &v, sizeof(int), False);
202 }
203
204 /* Return the profiling level */
205
206 static void profilelevel_cb(int msg_type, pid_t pid, void *buf, size_t len)
207 {
208         int level;
209         const char *s;
210
211         num_replies++;
212
213         if (len != sizeof(int)) {
214                 fprintf(stderr, "invalid message length %ld returned\n", 
215                         (unsigned long)len);
216                 return;
217         }
218
219         memcpy(&level, buf, sizeof(int));
220
221         switch (level) {
222         case 0:
223                 s = "not enabled";
224                 break;
225         case 1:
226                 s = "off";
227                 break;
228         case 3:
229                 s = "count only";
230                 break;
231         case 7:
232                 s = "count and time";
233                 break;
234         default:
235                 s = "BOGUS";
236                 break;
237         }
238         
239         printf("Profiling %s on pid %u\n",s,(unsigned int)pid);
240 }
241
242 static void profilelevel_rqst(int msg_type, pid_t pid, void *buf, size_t len)
243 {
244         int v = 0;
245
246         /* Send back a dummy reply */
247
248         send_message(pid, MSG_PROFILELEVEL, &v, sizeof(int), False);
249 }
250
251 static BOOL do_profilelevel(const pid_t pid, const int argc, const char **argv)
252 {
253         if (argc != 1) {
254                 fprintf(stderr, "Usage: smbcontrol <dest> profilelevel\n");
255                 return False;
256         }
257
258         /* Send a message and register our interest in a reply */
259
260         if (!send_message(pid, MSG_REQ_PROFILELEVEL, NULL, 0, False))
261                 return False;
262
263         message_register(MSG_PROFILELEVEL, profilelevel_cb);
264         message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst);
265
266         wait_replies(pid == 0);
267
268         /* No replies were received within the timeout period */
269
270         if (num_replies == 0)
271                 printf("No replies received\n");
272
273         message_deregister(MSG_PROFILE);
274
275         return num_replies;
276 }
277
278 /* Display debug level settings */
279
280 static BOOL do_debuglevel(const pid_t pid, const int argc, const char **argv)
281 {
282         if (argc != 1) {
283                 fprintf(stderr, "Usage: smbcontrol <dest> debuglevel\n");
284                 return False;
285         }
286
287         /* Send a message and register our interest in a reply */
288
289         if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False))
290                 return False;
291
292         message_register(MSG_DEBUGLEVEL, print_pid_string_cb);
293
294         wait_replies(pid == 0);
295
296         /* No replies were received within the timeout period */
297
298         if (num_replies == 0)
299                 printf("No replies received\n");
300
301         message_deregister(MSG_DEBUGLEVEL);
302
303         return num_replies;
304 }
305
306 /* Send a print notify message */
307
308 static BOOL do_printnotify(const pid_t pid, const int argc, const char **argv)
309 {
310         const char *cmd;
311
312         /* Check for subcommand */
313
314         if (argc == 1) {
315                 fprintf(stderr, "Must specify subcommand:\n");
316                 fprintf(stderr, "\tqueuepause <printername>\n");
317                 fprintf(stderr, "\tqueueresume <printername>\n");
318                 fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
319                 fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
320                 fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
321                 fprintf(stderr, "\tprinter <printername> <comment|port|"
322                         "driver> <value>\n");
323                 
324                 return False;
325         }
326
327         cmd = argv[1];
328
329         if (strcmp(cmd, "queuepause") == 0) {
330
331                 if (argc != 3) {
332                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
333                                 " queuepause <printername>\n");
334                         return False;
335                 }
336                 
337                 notify_printer_status_byname(argv[2], PRINTER_STATUS_PAUSED);
338
339                 goto send;
340
341         } else if (strcmp(cmd, "queueresume") == 0) {
342
343                 if (argc != 3) {
344                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
345                                 " queuereume <printername>\n");
346                         return False;
347                 }
348                 
349                 notify_printer_status_byname(argv[2], PRINTER_STATUS_OK);
350
351                 goto send;
352
353         } else if (strcmp(cmd, "jobpause") == 0) {
354                 int jobid;
355
356                 if (argc != 4) {
357                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
358                                 " jobpause <printername> <unix-jobid>\n");
359                         return False;
360                 }
361
362                 jobid = atoi(argv[3]);
363
364                 notify_job_status_byname(
365                         argv[2], jobid, JOB_STATUS_PAUSED, 
366                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
367
368                 goto send;
369
370         } else if (strcmp(cmd, "jobresume") == 0) {
371                 int jobid;
372
373                 if (argc != 4) {
374                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
375                                 " jobpause <printername> <unix-jobid>\n");
376                         return False;
377                 }
378
379                 jobid = atoi(argv[3]);
380
381                 notify_job_status_byname(
382                         argv[2], jobid, JOB_STATUS_QUEUED, 
383                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
384
385                 goto send;
386
387         } else if (strcmp(cmd, "jobdelete") == 0) {
388                 int jobid;
389
390                 if (argc != 4) {
391                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify"
392                                 " jobpause <printername> <unix-jobid>\n");
393                         return False;
394                 }
395
396                 jobid = atoi(argv[3]);
397
398                 notify_job_status_byname(
399                         argv[2], jobid, JOB_STATUS_DELETING,
400                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
401                 
402                 notify_job_status_byname(
403                         argv[2], jobid, JOB_STATUS_DELETING|
404                         JOB_STATUS_DELETED,
405                         SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
406
407                 goto send;
408
409         } else if (strcmp(cmd, "printer") == 0) {
410                 uint32 attribute;
411                 
412                 if (argc != 5) {
413                         fprintf(stderr, "Usage: smbcontrol <dest> printnotify "
414                                 "printer <printername> <comment|port|driver> "
415                                 "<value>\n");
416                         return False;
417                 }
418
419                 if (strcmp(argv[3], "comment") == 0) {
420                         attribute = PRINTER_NOTIFY_COMMENT;
421                 } else if (strcmp(argv[3], "port") == 0) {
422                         attribute = PRINTER_NOTIFY_PORT_NAME;
423                 } else if (strcmp(argv[3], "driver") == 0) {
424                         attribute = PRINTER_NOTIFY_DRIVER_NAME;
425                 } else {
426                         fprintf(stderr, "Invalid printer command '%s'\n",
427                                 argv[3]);
428                         return False;
429                 }
430
431                 notify_printer_byname(argv[2], attribute, argv[4]);
432
433                 goto send;
434         }
435
436         fprintf(stderr, "Invalid subcommand '%s'\n", cmd);
437         return False;
438
439 send:
440         print_notify_send_messages(0);
441         return True;
442 }
443
444 /* Close a share */
445
446 static BOOL do_closeshare(const pid_t pid, const int argc, const char **argv)
447 {
448         if (argc != 2) {
449                 fprintf(stderr, "Usage: smbcontrol <dest> close-share "
450                         "<sharename>\n");
451                 return False;
452         }
453
454         return send_message(
455                 pid, MSG_SMB_FORCE_TDIS, argv[1], strlen(argv[1]) + 1, False);
456 }
457
458 /* Force a SAM synchronisation */
459
460 static BOOL do_samsync(const pid_t pid, const int argc, const char **argv)
461 {
462         if (argc != 1) {
463                 fprintf(stderr, "Usage: smbcontrol <dest> samsync\n");
464                 return False;
465         }
466
467         return send_message(
468                 pid, MSG_SMB_SAM_SYNC, NULL, 0, False);
469 }
470
471 /* Force a SAM replication */
472
473 static BOOL do_samrepl(const pid_t pid, const int argc, const char **argv)
474 {
475         if (argc != 1) {
476                 fprintf(stderr, "Usage: smbcontrol <dest> samrepl\n");
477                 return False;
478         }
479
480         return send_message(
481                 pid, MSG_SMB_SAM_REPL, NULL, 0, False);
482 }
483
484 /* Display talloc pool usage */
485
486 static BOOL do_poolusage(const pid_t pid, const int argc, const char **argv)
487 {
488         if (argc != 1) {
489                 fprintf(stderr, "Usage: smbcontrol <dest> pool-usage\n");
490                 return False;
491         }
492
493         /* Send a message and register our interest in a reply */
494
495         if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False))
496                 return False;
497
498         message_register(MSG_POOL_USAGE, print_string_cb);
499
500         wait_replies(pid == 0);
501
502         /* No replies were received within the timeout period */
503
504         if (num_replies == 0)
505                 printf("No replies received\n");
506
507         message_deregister(MSG_POOL_USAGE);
508
509         return num_replies;
510 }
511
512 /* Perform a dmalloc mark */
513
514 static BOOL do_dmalloc_mark(const pid_t pid, const int argc, const char **argv)
515 {
516         if (argc != 1) {
517                 fprintf(stderr, "Usage: smbcontrol <dest> dmalloc-mark\n");
518                 return False;
519         }
520
521         return send_message(
522                 pid, MSG_REQ_DMALLOC_MARK, NULL, 0, False);
523 }
524
525 /* Perform a dmalloc changed */
526
527 static BOOL do_dmalloc_changed(const pid_t pid, const int argc, const char **argv)
528 {
529         if (argc != 1) {
530                 fprintf(stderr, "Usage: smbcontrol <dest> "
531                         "dmalloc-log-changed\n");
532                 return False;
533         }
534
535         return send_message(
536                 pid, MSG_REQ_DMALLOC_LOG_CHANGED, NULL, 0, False);
537 }
538
539 /* Shutdown a server process */
540
541 static BOOL do_shutdown(const pid_t pid, const int argc, const char **argv)
542 {
543         if (argc != 1) {
544                 fprintf(stderr, "Usage: smbcontrol <dest> shutdown\n");
545                 return False;
546         }
547
548         return send_message(pid, MSG_SHUTDOWN, NULL, 0, False);
549 }
550
551 /* Notify a driver upgrade */
552
553 static BOOL do_drvupgrade(const pid_t pid, const int argc, const char **argv)
554 {
555         if (argc != 2) {
556                 fprintf(stderr, "Usage: smbcontrol <dest> drvupgrade "
557                         "<driver-name>\n");
558                 return False;
559         }
560
561         return send_message(
562                 pid, MSG_DEBUG, argv[1], strlen(argv[1]) + 1, False);
563 }
564
565 static BOOL do_reload_config(const pid_t pid, const int argc, const char **argv)
566 {
567         if (argc != 1) {
568                 fprintf(stderr, "Usage: smbcontrol <dest> reload-config\n");
569                 return False;
570         }
571
572         return send_message(pid, MSG_SMB_CONF_UPDATED, NULL, 0, False);
573 }
574
575 static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
576 {
577         fstring unix_name;
578         memset( (char *)n, '\0', sizeof(struct nmb_name) );
579         fstrcpy(unix_name, name);
580         strupper_m(unix_name);
581         push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
582         n->name_type = (unsigned int)type & 0xFF;
583         push_ascii(n->scope,  global_scope(), 64, STR_TERMINATE);
584 }
585
586 static BOOL do_nodestatus(const pid_t pid, const int argc,
587                           const char **argv)
588 {
589         struct packet_struct p;
590
591         if (argc != 2) {
592                 fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
593                 return False;
594         }
595
596         ZERO_STRUCT(p);
597
598         p.ip = *interpret_addr2(argv[1]);
599         p.port = 137;
600         p.packet_type = NMB_PACKET;
601
602         p.packet.nmb.header.name_trn_id = 10;
603         p.packet.nmb.header.opcode = 0;
604         p.packet.nmb.header.response = False;
605         p.packet.nmb.header.nm_flags.bcast = False;
606         p.packet.nmb.header.nm_flags.recursion_available = False;
607         p.packet.nmb.header.nm_flags.recursion_desired = False;
608         p.packet.nmb.header.nm_flags.trunc = False;
609         p.packet.nmb.header.nm_flags.authoritative = False;
610         p.packet.nmb.header.rcode = 0;
611         p.packet.nmb.header.qdcount = 1;
612         p.packet.nmb.header.ancount = 0;
613         p.packet.nmb.header.nscount = 0;
614         p.packet.nmb.header.arcount = 0;
615         my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
616         p.packet.nmb.question.question_type = 0x21;
617         p.packet.nmb.question.question_class = 0x1;
618
619         return send_message(pid, MSG_SEND_PACKET, &p, sizeof(p), False);
620 }
621
622 /* A list of message type supported */
623
624 static const struct {
625         const char *name;       /* Option name */
626         BOOL (*fn)(const pid_t pid, const int argc, const char **argv);
627         const char *help;       /* Short help text */
628 } msg_types[] = {
629         { "debug", do_debug, "Set debuglevel"  },
630         { "force-election", do_election,
631           "Force a browse election" },
632         { "ping", do_ping, "Elicit a response" },
633         { "profile", do_profile, "" },
634         { "profilelevel", do_profilelevel, "" },
635         { "debuglevel", do_debuglevel, "Display current debuglevels" },
636         { "printnotify", do_printnotify, "Send a print notify message" },
637         { "close-share", do_closeshare, "Forcibly disconnect a share" },
638         { "samsync", do_samsync, "Initiate SAM synchronisation" },
639         { "samrepl", do_samrepl, "Initiate SAM replication" },
640         { "pool-usage", do_poolusage, "Display talloc memory usage" },
641         { "dmalloc-mark", do_dmalloc_mark, "" },
642         { "dmalloc-log-changed", do_dmalloc_changed, "" },
643         { "shutdown", do_shutdown, "Shut down daemon" },
644         { "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
645         { "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
646         { "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
647         { "noop", do_noop, "Do nothing" },
648         { NULL }
649 };
650
651 /* Display usage information */
652
653 static void usage(poptContext *pc)
654 {
655         int i;
656
657         poptPrintHelp(*pc, stderr, 0);
658
659         fprintf(stderr, "\n");
660         fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\" or a "
661                 "process ID\n");
662
663         fprintf(stderr, "\n");
664         fprintf(stderr, "<message-type> is one of:\n");
665
666         for (i = 0; msg_types[i].name; i++) 
667             fprintf(stderr, "\t%-30s%s\n", msg_types[i].name, 
668                     msg_types[i].help);
669
670         fprintf(stderr, "\n");
671
672         exit(1);
673 }
674
675 /* Return the pid number for a string destination */
676
677 static pid_t parse_dest(const char *dest)
678 {
679         pid_t pid;
680
681         /* Zero is a special return value for broadcast smbd */
682
683         if (strequal(dest, "smbd"))
684                 return 0;
685
686         /* Try self - useful for testing */
687
688         if (strequal(dest, "self"))
689                 return sys_getpid();
690
691         /* Check for numeric pid number */
692
693         if ((pid = atoi(dest)) != 0)
694                 return pid;
695
696         /* Look up other destinations in pidfile directory */
697
698         if ((pid = pidfile_pid(dest)) != 0)
699                 return pid;
700
701         fprintf(stderr,"Can't find pid for destination '%s'\n", dest);
702
703         return -1;
704 }       
705
706 /* Execute smbcontrol command */
707
708 static BOOL do_command(int argc, const char **argv)
709 {
710         const char *dest = argv[0], *command = argv[1];
711         pid_t pid;
712         int i;
713
714         /* Check destination */
715
716         if ((pid = parse_dest(dest)) == -1)
717                 return False;
718
719         /* Check command */
720
721         for (i = 0; msg_types[i].name; i++) {
722                 if (strequal(command, msg_types[i].name))
723                         return msg_types[i].fn(pid, argc - 1, argv + 1);
724         }
725
726         fprintf(stderr, "smbcontrol: unknown command '%s'\n", command);
727
728         return False;
729 }
730
731 /* Main program */
732
733 int main(int argc, const char **argv)
734 {
735         poptContext pc;
736         int opt;
737
738         static struct poptOption wbinfo_options[] = {
739                 { "timeout", 't', POPT_ARG_INT, &timeout, 't', 
740                   "Set timeout value in seconds", "TIMEOUT" },
741
742                 { "configfile", 's', POPT_ARG_STRING, NULL, 's', 
743                   "Use alternative configuration file", "CONFIGFILE" },
744
745                 POPT_TABLEEND
746         };
747
748         struct poptOption options[] = {
749                 { NULL, 0, POPT_ARG_INCLUDE_TABLE, wbinfo_options, 0, 
750                   "Options" },
751
752                 POPT_AUTOHELP
753                 POPT_COMMON_VERSION
754                 POPT_TABLEEND
755         };
756
757         setup_logging(argv[0],True);
758         
759         /* Parse command line arguments using popt */
760
761         pc = poptGetContext(
762                 "smbcontrol", argc, (const char **)argv, options, 0);
763
764         poptSetOtherOptionHelp(pc, "[OPTION...] <destination> <message-type> "
765                                "<parameters>");
766
767         if (argc == 1)
768                 usage(&pc);
769
770         while ((opt = poptGetNextOpt(pc)) != -1) {
771                 switch(opt) {
772                 case 't':       /* --timeout */
773                         argc -= 2;
774                         break;
775                 case 's':       /* --configfile */
776                         pstrcpy(dyn_CONFIGFILE, poptGetOptArg(pc));
777                         argc -= 2;
778                         break;
779                 default:
780                         fprintf(stderr, "Invalid option\n");
781                         poptPrintHelp(pc, stderr, 0);
782                         break;
783                 }
784         }
785
786         /* We should now have the remaining command line arguments in
787            argv.  The argc parameter should have been decremented to the
788            correct value in the above switch statement. */
789
790         argv = (const char **)poptGetArgs(pc);
791         argc--;                 /* Don't forget about argv[0] */
792
793         if (argc == 1)
794                 usage(&pc);
795
796         lp_load(dyn_CONFIGFILE,False,False,False);
797
798         /* Need to invert sense of return code -- samba
799          * routines mostly return True==1 for success, but
800          * shell needs 0. */ 
801         
802         return !do_command(argc, argv);
803 }