smbstatus: move the output of the content to their own methods
[Samba.git] / source3 / utils / status.c
blob05172734812aa3ca2d3f0b1247571ac798e9e80d
1 /*
2 Unix SMB/CIFS implementation.
3 status reporting
4 Copyright (C) Andrew Tridgell 1994-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 Revision History:
21 12 aug 96: Erik.Devriendt@te6.siemens.be
22 added support for shared memory implementation of share mode locking
24 21-Jul-1998: rsharpe@ns.aus.com (Richard Sharpe)
25 Added -L (locks only) -S (shares only) flags and code
30 * This program reports current SMB connections
33 #include "includes.h"
34 #include "lib/util/server_id.h"
35 #include "smbd/globals.h"
36 #include "system/filesys.h"
37 #include "lib/cmdline/cmdline.h"
38 #include "dbwrap/dbwrap.h"
39 #include "dbwrap/dbwrap_open.h"
40 #include "../libcli/security/security.h"
41 #include "session.h"
42 #include "locking/share_mode_lock.h"
43 #include "locking/proto.h"
44 #include "messages.h"
45 #include "librpc/gen_ndr/open_files.h"
46 #include "smbd/smbd.h"
47 #include "librpc/gen_ndr/notify.h"
48 #include "conn_tdb.h"
49 #include "serverid.h"
50 #include "status_profile.h"
51 #include "status.h"
52 #include "smbd/notifyd/notifyd_db.h"
53 #include "cmdline_contexts.h"
54 #include "locking/leases_db.h"
55 #include "lib/util/string_wrappers.h"
57 #define SMB_MAXPIDS 2048
58 static uid_t Ucrit_uid = 0; /* added by OH */
59 static struct server_id Ucrit_pid[SMB_MAXPIDS]; /* Ugly !!! */ /* added by OH */
60 static int Ucrit_MaxPid=0; /* added by OH */
61 static unsigned int Ucrit_IsActive = 0; /* added by OH */
63 static bool verbose, brief;
64 static bool shares_only; /* Added by RJS */
65 static bool locks_only; /* Added by RJS */
66 static bool processes_only;
67 static bool show_brl;
68 static bool numeric_only;
69 static bool do_checks = true;
71 const char *username = NULL;
73 /* added by OH */
74 static void Ucrit_addUid(uid_t uid)
76 Ucrit_uid = uid;
77 Ucrit_IsActive = 1;
80 static unsigned int Ucrit_checkUid(uid_t uid)
82 if ( !Ucrit_IsActive )
83 return 1;
85 if ( uid == Ucrit_uid )
86 return 1;
88 return 0;
91 static unsigned int Ucrit_checkPid(struct server_id pid)
93 int i;
95 if ( !Ucrit_IsActive )
96 return 1;
98 for (i=0;i<Ucrit_MaxPid;i++) {
99 if (server_id_equal(&pid, &Ucrit_pid[i])) {
100 return 1;
104 return 0;
107 static bool Ucrit_addPid( struct server_id pid )
109 if ( !Ucrit_IsActive )
110 return True;
112 if ( Ucrit_MaxPid >= SMB_MAXPIDS ) {
113 fprintf(stderr, "ERROR: More than %d pids for user %s!\n",
114 SMB_MAXPIDS, uidtoname(Ucrit_uid));
116 return False;
119 Ucrit_pid[Ucrit_MaxPid++] = pid;
121 return True;
124 static int print_share_mode_stdout(struct traverse_state *state,
125 const char *pid,
126 const char *user_name,
127 const char *denymode,
128 int access_mask,
129 const char *rw,
130 const char *oplock,
131 const char *servicepath,
132 const char *filename,
133 const char *timestr)
135 if (state->first) {
136 d_printf("\nLocked files:\n");
137 d_printf("Pid User(ID) DenyMode Access R/W Oplock SharePath Name Time\n");
138 d_printf("--------------------------------------------------------------------------------------------------\n");
140 state->first = false;
143 d_printf("%-11s %-9s %-10s 0x%-8x %-10s %-14s %s %s %s",
144 pid, user_name, denymode, access_mask, rw, oplock,
145 servicepath, filename, timestr);
146 return 0;
149 static int prepare_share_mode(struct traverse_state *state)
151 /* only print header line if there are open files */
152 state->first = true;
154 return 0;
157 static int print_share_mode(struct file_id fid,
158 const struct share_mode_data *d,
159 const struct share_mode_entry *e,
160 void *private_data)
162 const char *denymode = NULL;
163 uint denymode_int;
164 const char *oplock = NULL;
165 const char *pid = NULL;
166 const char *rw = NULL;
167 const char *filename = NULL;
168 const char *timestr = NULL;
169 const char *user_str = NULL;
170 struct traverse_state *state = (struct traverse_state *)private_data;
172 TALLOC_CTX *tmp_ctx = talloc_stackframe();
173 if (tmp_ctx == NULL) {
174 return -1;
177 if (do_checks && !is_valid_share_mode_entry(e)) {
178 TALLOC_FREE(tmp_ctx);
179 return 0;
182 if (do_checks && !serverid_exists(&e->pid)) {
183 /* the process for this entry does not exist any more */
184 TALLOC_FREE(tmp_ctx);
185 return 0;
188 if (Ucrit_checkPid(e->pid)) {
189 struct server_id_buf tmp;
190 pid = server_id_str_buf(e->pid, &tmp);
191 if (state->resolve_uids) {
192 user_str = talloc_asprintf(tmp_ctx, "%s", uidtoname(e->uid));
193 } else {
194 user_str = talloc_asprintf(tmp_ctx, "%u", (unsigned int)e->uid);
196 if (user_str == NULL) {
197 TALLOC_FREE(tmp_ctx);
198 return -1;
201 denymode_int = map_share_mode_to_deny_mode(e->share_access,
202 e->private_options);
203 switch (denymode_int) {
204 case DENY_NONE:
205 denymode = "DENY_NONE";
206 break;
207 case DENY_ALL:
208 denymode = "DENY_ALL";
209 break;
210 case DENY_DOS:
211 denymode = "DENY_DOS";
212 break;
213 case DENY_READ:
214 denymode = "DENY_READ";
215 break;
216 case DENY_WRITE:
217 denymode = "DENY_WRITE";
218 break;
219 case DENY_FCB:
220 denymode = "DENY_FCB";
221 break;
222 default: {
223 denymode = talloc_asprintf(tmp_ctx,
224 "UNKNOWN(0x%08x)",
225 denymode_int);
226 if (denymode == NULL) {
227 TALLOC_FREE(tmp_ctx);
228 return -1;
230 fprintf(stderr,
231 "unknown-please report ! "
232 "e->share_access = 0x%x, "
233 "e->private_options = 0x%x\n",
234 (unsigned int)e->share_access,
235 (unsigned int)e->private_options);
236 break;
239 filename = talloc_asprintf(tmp_ctx,
240 "%s%s",
241 d->base_name,
242 (d->stream_name != NULL) ? d->stream_name : "");
243 if (filename == NULL) {
244 TALLOC_FREE(tmp_ctx);
245 return -1;
247 if ((e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))==
248 (FILE_READ_DATA|FILE_WRITE_DATA)) {
249 rw = "RDWR";
250 } else if (e->access_mask & FILE_WRITE_DATA) {
251 rw = "WRONLY";
252 } else {
253 rw = "RDONLY";
256 if (e->op_type & BATCH_OPLOCK) {
257 oplock = "BATCH";
258 } else if (e->op_type & EXCLUSIVE_OPLOCK) {
259 oplock = "EXCLUSIVE";
260 } else if (e->op_type & LEVEL_II_OPLOCK) {
261 oplock = "LEVEL_II";
262 } else if (e->op_type == LEASE_OPLOCK) {
263 NTSTATUS status;
264 uint32_t lstate;
266 status = leases_db_get(
267 &e->client_guid,
268 &e->lease_key,
269 &d->id,
270 &lstate, /* current_state */
271 NULL, /* breaking */
272 NULL, /* breaking_to_requested */
273 NULL, /* breaking_to_required */
274 NULL, /* lease_version */
275 NULL); /* epoch */
277 if (NT_STATUS_IS_OK(status)) {
278 oplock = talloc_asprintf(tmp_ctx, "LEASE(%s%s%s)%s%s%s",
279 (lstate & SMB2_LEASE_READ)?"R":"",
280 (lstate & SMB2_LEASE_WRITE)?"W":"",
281 (lstate & SMB2_LEASE_HANDLE)?"H":"",
282 (lstate & SMB2_LEASE_READ)?"":" ",
283 (lstate & SMB2_LEASE_WRITE)?"":" ",
284 (lstate & SMB2_LEASE_HANDLE)?"":" ");
285 } else {
286 oplock = "LEASE STATE UNKNOWN";
288 } else {
289 oplock = "NONE";
292 timestr = time_to_asc((time_t)e->time.tv_sec);
293 print_share_mode_stdout(state,
294 pid,
295 user_str,
296 denymode,
297 (unsigned int)e->access_mask,
299 oplock,
300 d->servicepath,
301 filename,
302 timestr);
304 TALLOC_FREE(tmp_ctx);
305 return 0;
308 static void print_brl_stdout(struct traverse_state *state,
309 char *pid,
310 char *id,
311 const char *desc,
312 intmax_t start,
313 intmax_t size,
314 const char *sharepath,
315 char *fname)
317 if (state->first) {
318 d_printf("Byte range locks:\n");
319 d_printf("Pid dev:inode R/W start size SharePath Name\n");
320 d_printf("--------------------------------------------------------------------------------\n");
322 state->first = false;
324 d_printf("%-10s %-15s %-4s %-9jd %-9jd %-24s %-24s\n",
325 pid, id, desc, start, size, sharepath, fname);
328 static int prepare_brl(struct traverse_state *state)
330 /* only print header line if there are locked files */
331 state->first = true;
333 return 0;
336 static void print_brl(struct file_id id,
337 struct server_id pid,
338 enum brl_type lock_type,
339 enum brl_flavour lock_flav,
340 br_off start,
341 br_off size,
342 void *private_data)
344 unsigned int i;
345 static const struct {
346 enum brl_type lock_type;
347 const char *desc;
348 } lock_types[] = {
349 { READ_LOCK, "R" },
350 { WRITE_LOCK, "W" },
351 { UNLOCK_LOCK, "U" }
353 const char *desc="X";
354 const char *sharepath = "";
355 char *fname = NULL;
356 struct share_mode_lock *share_mode;
357 struct server_id_buf tmp;
358 struct file_id_buf ftmp;
359 struct traverse_state *state = (struct traverse_state *)private_data;
361 share_mode = fetch_share_mode_unlocked(NULL, id);
362 if (share_mode) {
363 fname = share_mode_filename(NULL, share_mode);
364 } else {
365 fname = talloc_strdup(NULL, "");
366 if (fname == NULL) {
367 return;
371 for (i=0;i<ARRAY_SIZE(lock_types);i++) {
372 if (lock_type == lock_types[i].lock_type) {
373 desc = lock_types[i].desc;
377 print_brl_stdout(state,
378 server_id_str_buf(pid, &tmp),
379 file_id_str_buf(id, &ftmp),
380 desc,
381 (intmax_t)start,
382 (intmax_t)size,
383 sharepath,
384 fname);
386 TALLOC_FREE(fname);
387 TALLOC_FREE(share_mode);
390 static const char *session_dialect_str(uint16_t dialect)
392 static fstring unknown_dialect;
394 switch(dialect){
395 case SMB2_DIALECT_REVISION_000:
396 return "NT1";
397 case SMB2_DIALECT_REVISION_202:
398 return "SMB2_02";
399 case SMB2_DIALECT_REVISION_210:
400 return "SMB2_10";
401 case SMB2_DIALECT_REVISION_222:
402 return "SMB2_22";
403 case SMB2_DIALECT_REVISION_224:
404 return "SMB2_24";
405 case SMB3_DIALECT_REVISION_300:
406 return "SMB3_00";
407 case SMB3_DIALECT_REVISION_302:
408 return "SMB3_02";
409 case SMB3_DIALECT_REVISION_310:
410 return "SMB3_10";
411 case SMB3_DIALECT_REVISION_311:
412 return "SMB3_11";
415 fstr_sprintf(unknown_dialect, "Unknown (0x%04x)", dialect);
416 return unknown_dialect;
419 static int traverse_connections_stdout(struct traverse_state *state,
420 const char *servicename,
421 char *server_id,
422 const char *machine,
423 const char *timestr,
424 const char *encryption,
425 const char *signing)
427 d_printf("%-12s %-7s %-13s %-32s %-12s %-12s\n",
428 servicename, server_id, machine, timestr, encryption, signing);
430 return 0;
433 static int prepare_connections(struct traverse_state *state)
435 /* always print header line */
436 d_printf("\n%-12s %-7s %-13s %-32s %-12s %-12s\n", "Service", "pid", "Machine", "Connected at", "Encryption", "Signing");
437 d_printf("---------------------------------------------------------------------------------------------\n");
439 return 0;
442 static int traverse_connections(const struct connections_data *crec,
443 void *private_data)
445 struct server_id_buf tmp;
446 char *timestr = NULL;
447 int result = 0;
448 const char *encryption = "-";
449 const char *signing = "-";
450 struct traverse_state *state = (struct traverse_state *)private_data;
452 TALLOC_CTX *tmp_ctx = talloc_stackframe();
453 if (tmp_ctx == NULL) {
454 return -1;
457 if (crec->cnum == TID_FIELD_INVALID) {
458 TALLOC_FREE(tmp_ctx);
459 return 0;
462 if (do_checks &&
463 (!process_exists(crec->pid) || !Ucrit_checkUid(crec->uid))) {
464 TALLOC_FREE(tmp_ctx);
465 return 0;
468 timestr = timestring(tmp_ctx, crec->start);
469 if (timestr == NULL) {
470 TALLOC_FREE(tmp_ctx);
471 return -1;
474 if (smbXsrv_is_encrypted(crec->encryption_flags)) {
475 switch (crec->cipher) {
476 case SMB_ENCRYPTION_GSSAPI:
477 encryption = "GSSAPI";
478 break;
479 case SMB2_ENCRYPTION_AES128_CCM:
480 encryption = "AES-128-CCM";
481 break;
482 case SMB2_ENCRYPTION_AES128_GCM:
483 encryption = "AES-128-GCM";
484 break;
485 default:
486 encryption = "???";
487 result = -1;
488 break;
492 if (smbXsrv_is_signed(crec->signing_flags)) {
493 switch (crec->signing) {
494 case SMB2_SIGNING_MD5_SMB1:
495 signing = "HMAC-MD5";
496 break;
497 case SMB2_SIGNING_HMAC_SHA256:
498 signing = "HMAC-SHA256";
499 break;
500 case SMB2_SIGNING_AES128_CMAC:
501 signing = "AES-128-CMAC";
502 break;
503 case SMB2_SIGNING_AES128_GMAC:
504 signing = "AES-128-GMAC";
505 break;
506 default:
507 signing = "???";
508 result = -1;
509 break;
513 result = traverse_connections_stdout(state,
514 crec->servicename,
515 server_id_str_buf(crec->pid, &tmp),
516 crec->machine,
517 timestr,
518 encryption,
519 signing);
521 TALLOC_FREE(timestr);
522 TALLOC_FREE(tmp_ctx);
524 return result;
527 static int traverse_sessionid_stdout(struct traverse_state *state,
528 char *server_id,
529 char *uid_gid_str,
530 char *machine_hostname,
531 const char *dialect,
532 const char *encryption,
533 const char *signing)
535 d_printf("%-7s %-25s %-41s %-17s %-20s %-21s\n",
536 server_id, uid_gid_str, machine_hostname, dialect, encryption,
537 signing);
539 return 0;
542 static int prepare_sessionid(struct traverse_state *state)
544 /* always print header line */
545 d_printf("\nSamba version %s\n",samba_version_string());
546 d_printf("%-7s %-12s %-12s %-41s %-17s %-20s %-21s\n", "PID", "Username", "Group", "Machine", "Protocol Version", "Encryption", "Signing");
547 d_printf("----------------------------------------------------------------------------------------------------------------------------------------\n");
549 return 0;
553 static int traverse_sessionid(const char *key, struct sessionid *session,
554 void *private_data)
556 fstring uid_gid_str;
557 struct server_id_buf tmp;
558 char *machine_hostname = NULL;
559 int result = 0;
560 const char *encryption = "-";
561 const char *signing = "-";
562 struct traverse_state *state = (struct traverse_state *)private_data;
564 TALLOC_CTX *tmp_ctx = talloc_stackframe();
565 if (tmp_ctx == NULL) {
566 return -1;
569 if (do_checks &&
570 (!process_exists(session->pid) ||
571 !Ucrit_checkUid(session->uid))) {
572 TALLOC_FREE(tmp_ctx);
573 return 0;
576 Ucrit_addPid(session->pid);
578 if (numeric_only) {
579 fstr_sprintf(uid_gid_str, "%-12u %-12u",
580 (unsigned int)session->uid,
581 (unsigned int)session->gid);
582 } else {
583 if (session->uid == -1 && session->gid == -1) {
585 * The session is not fully authenticated yet.
587 fstrcpy(uid_gid_str, "(auth in progress)");
588 } else {
590 * In theory it should not happen that one of
591 * session->uid and session->gid is valid (ie != -1)
592 * while the other is not (ie = -1), so we a check for
593 * that case that bails out would be reasonable.
595 const char *uid_name = "-1";
596 const char *gid_name = "-1";
598 if (session->uid != -1) {
599 uid_name = uidtoname(session->uid);
600 if (uid_name == NULL) {
601 TALLOC_FREE(tmp_ctx);
602 return -1;
605 if (session->gid != -1) {
606 gid_name = gidtoname(session->gid);
607 if (gid_name == NULL) {
608 TALLOC_FREE(tmp_ctx);
609 return -1;
612 fstr_sprintf(uid_gid_str, "%-12s %-12s",
613 uid_name, gid_name);
617 machine_hostname = talloc_asprintf(tmp_ctx, "%s (%s)",
618 session->remote_machine,
619 session->hostname);
620 if (machine_hostname == NULL) {
621 TALLOC_FREE(tmp_ctx);
622 return -1;
625 if (smbXsrv_is_encrypted(session->encryption_flags)) {
626 switch (session->cipher) {
627 case SMB2_ENCRYPTION_AES128_CCM:
628 encryption = "AES-128-CCM";
629 break;
630 case SMB2_ENCRYPTION_AES128_GCM:
631 encryption = "AES-128-GCM";
632 break;
633 case SMB2_ENCRYPTION_AES256_CCM:
634 encryption = "AES-256-CCM";
635 break;
636 case SMB2_ENCRYPTION_AES256_GCM:
637 encryption = "AES-256-GCM";
638 break;
639 default:
640 encryption = "???";
641 result = -1;
642 break;
644 } else if (smbXsrv_is_partially_encrypted(session->encryption_flags)) {
645 switch (session->cipher) {
646 case SMB_ENCRYPTION_GSSAPI:
647 encryption = "partial(GSSAPI)";
648 break;
649 case SMB2_ENCRYPTION_AES128_CCM:
650 encryption = "partial(AES-128-CCM)";
651 break;
652 case SMB2_ENCRYPTION_AES128_GCM:
653 encryption = "partial(AES-128-GCM)";
654 break;
655 case SMB2_ENCRYPTION_AES256_CCM:
656 encryption = "partial(AES-256-CCM)";
657 break;
658 case SMB2_ENCRYPTION_AES256_GCM:
659 encryption = "partial(AES-256-GCM)";
660 break;
661 default:
662 encryption = "???";
663 result = -1;
664 break;
668 if (smbXsrv_is_signed(session->signing_flags)) {
669 switch (session->signing) {
670 case SMB2_SIGNING_MD5_SMB1:
671 signing = "HMAC-MD5";
672 break;
673 case SMB2_SIGNING_HMAC_SHA256:
674 signing = "HMAC-SHA256";
675 break;
676 case SMB2_SIGNING_AES128_CMAC:
677 signing = "AES-128-CMAC";
678 break;
679 case SMB2_SIGNING_AES128_GMAC:
680 signing = "AES-128-GMAC";
681 break;
682 default:
683 signing = "???";
684 result = -1;
685 break;
687 } else if (smbXsrv_is_partially_signed(session->signing_flags)) {
688 switch (session->signing) {
689 case SMB2_SIGNING_MD5_SMB1:
690 signing = "partial(HMAC-MD5)";
691 break;
692 case SMB2_SIGNING_HMAC_SHA256:
693 signing = "partial(HMAC-SHA256)";
694 break;
695 case SMB2_SIGNING_AES128_CMAC:
696 signing = "partial(AES-128-CMAC)";
697 break;
698 case SMB2_SIGNING_AES128_GMAC:
699 signing = "partial(AES-128-GMAC)";
700 break;
701 default:
702 signing = "???";
703 result = -1;
704 break;
709 traverse_sessionid_stdout(state,
710 server_id_str_buf(session->pid, &tmp),
711 uid_gid_str,
712 machine_hostname,
713 session_dialect_str(session->connection_dialect),
714 encryption,
715 signing);
717 TALLOC_FREE(machine_hostname);
718 TALLOC_FREE(tmp_ctx);
720 return result;
724 static bool print_notify_rec_stdout(struct traverse_state *state,
725 const char *path,
726 char *server_id_str,
727 unsigned filter,
728 unsigned subdir_filter)
730 d_printf("%s\\%s\\%x\\%x\n", path, server_id_str,
731 filter, subdir_filter);
733 return true;
736 static int prepare_notify(struct traverse_state *state)
738 /* don't print header line */
740 return 0;
743 static bool print_notify_rec(const char *path, struct server_id server,
744 const struct notify_instance *instance,
745 void *private_data)
747 struct server_id_buf idbuf;
748 struct traverse_state *state = (struct traverse_state *)private_data;
749 bool result;
751 result = print_notify_rec_stdout(state,
752 path,
753 server_id_str_buf(server, &idbuf),
754 (unsigned)instance->filter,
755 (unsigned)instance->subdir_filter);
757 return result;
760 enum {
761 OPT_RESOLVE_UIDS = 1000,
764 int main(int argc, const char *argv[])
766 int c;
767 int profile_only = 0;
768 bool show_processes, show_locks, show_shares;
769 bool show_notify = false;
770 poptContext pc = NULL;
771 struct traverse_state state = {0};
772 struct poptOption long_options[] = {
773 POPT_AUTOHELP
775 .longName = "processes",
776 .shortName = 'p',
777 .argInfo = POPT_ARG_NONE,
778 .arg = NULL,
779 .val = 'p',
780 .descrip = "Show processes only",
783 .longName = "verbose",
784 .shortName = 'v',
785 .argInfo = POPT_ARG_NONE,
786 .arg = NULL,
787 .val = 'v',
788 .descrip = "Be verbose",
791 .longName = "locks",
792 .shortName = 'L',
793 .argInfo = POPT_ARG_NONE,
794 .arg = NULL,
795 .val = 'L',
796 .descrip = "Show locks only",
799 .longName = "shares",
800 .shortName = 'S',
801 .argInfo = POPT_ARG_NONE,
802 .arg = NULL,
803 .val = 'S',
804 .descrip = "Show shares only",
807 .longName = "notify",
808 .shortName = 'N',
809 .argInfo = POPT_ARG_NONE,
810 .arg = NULL,
811 .val = 'N',
812 .descrip = "Show notifies",
815 .longName = "user",
816 .shortName = 'u',
817 .argInfo = POPT_ARG_STRING,
818 .arg = &username,
819 .val = 'u',
820 .descrip = "Switch to user",
823 .longName = "brief",
824 .shortName = 'b',
825 .argInfo = POPT_ARG_NONE,
826 .arg = NULL,
827 .val = 'b',
828 .descrip = "Be brief",
831 .longName = "profile",
832 .shortName = 'P',
833 .argInfo = POPT_ARG_NONE,
834 .arg = NULL,
835 .val = 'P',
836 .descrip = "Do profiling",
839 .longName = "profile-rates",
840 .shortName = 'R',
841 .argInfo = POPT_ARG_NONE,
842 .arg = NULL,
843 .val = 'R',
844 .descrip = "Show call rates",
847 .longName = "byterange",
848 .shortName = 'B',
849 .argInfo = POPT_ARG_NONE,
850 .arg = NULL,
851 .val = 'B',
852 .descrip = "Include byte range locks"
855 .longName = "numeric",
856 .shortName = 'n',
857 .argInfo = POPT_ARG_NONE,
858 .arg = NULL,
859 .val = 'n',
860 .descrip = "Numeric uid/gid"
863 .longName = "fast",
864 .shortName = 'f',
865 .argInfo = POPT_ARG_NONE,
866 .arg = NULL,
867 .val = 'f',
868 .descrip = "Skip checks if processes still exist"
871 .longName = "resolve-uids",
872 .shortName = 0,
873 .argInfo = POPT_ARG_NONE,
874 .arg = NULL,
875 .val = OPT_RESOLVE_UIDS,
876 .descrip = "Try to resolve UIDs to usernames"
878 POPT_COMMON_SAMBA
879 POPT_COMMON_VERSION
880 POPT_TABLEEND
882 TALLOC_CTX *frame = talloc_stackframe();
883 int ret = 0;
884 struct messaging_context *msg_ctx = NULL;
885 char *db_path;
886 bool ok;
888 state.first = true;
889 state.resolve_uids = false;
891 smb_init_locale();
893 ok = samba_cmdline_init(frame,
894 SAMBA_CMDLINE_CONFIG_CLIENT,
895 false /* require_smbconf */);
896 if (!ok) {
897 DBG_ERR("Failed to init cmdline parser!\n");
898 TALLOC_FREE(frame);
899 exit(1);
901 lp_set_cmdline("log level", "0");
903 pc = samba_popt_get_context(getprogname(),
904 argc,
905 argv,
906 long_options,
907 POPT_CONTEXT_KEEP_FIRST);
908 if (pc == NULL) {
909 DBG_ERR("Failed to setup popt context!\n");
910 TALLOC_FREE(frame);
911 exit(1);
914 while ((c = poptGetNextOpt(pc)) != -1) {
915 switch (c) {
916 case 'p':
917 processes_only = true;
918 break;
919 case 'v':
920 verbose = true;
921 break;
922 case 'L':
923 locks_only = true;
924 break;
925 case 'S':
926 shares_only = true;
927 break;
928 case 'N':
929 show_notify = true;
930 break;
931 case 'b':
932 brief = true;
933 break;
934 case 'u':
935 Ucrit_addUid(nametouid(poptGetOptArg(pc)));
936 break;
937 case 'P':
938 case 'R':
939 profile_only = c;
940 break;
941 case 'B':
942 show_brl = true;
943 break;
944 case 'n':
945 numeric_only = true;
946 break;
947 case 'f':
948 do_checks = false;
949 break;
950 case OPT_RESOLVE_UIDS:
951 state.resolve_uids = true;
952 break;
953 case POPT_ERROR_BADOPT:
954 fprintf(stderr, "\nInvalid option %s: %s\n\n",
955 poptBadOption(pc, 0), poptStrerror(c));
956 poptPrintUsage(pc, stderr, 0);
957 exit(1);
961 sec_init();
963 if (getuid() != geteuid()) {
964 fprintf(stderr, "smbstatus should not be run setuid\n");
965 ret = 1;
966 goto done;
969 if (getuid() != 0) {
970 fprintf(stderr, "smbstatus only works as root!\n");
971 ret = 1;
972 goto done;
975 /* setup the flags based on the possible combincations */
977 show_processes = !(shares_only || locks_only || profile_only) || processes_only;
978 show_locks = !(shares_only || processes_only || profile_only) || locks_only;
979 show_shares = !(processes_only || locks_only || profile_only) || shares_only;
981 if ( username )
982 Ucrit_addUid( nametouid(username) );
984 if (verbose) {
985 d_printf("using configfile = %s\n", get_dyn_CONFIGFILE());
988 msg_ctx = cmdline_messaging_context(get_dyn_CONFIGFILE());
989 if (msg_ctx == NULL) {
990 fprintf(stderr, "Could not initialize messaging, not root?\n");
991 ret = -1;
992 goto done;
995 switch (profile_only) {
996 case 'P':
997 /* Dump profile data */
998 ok = status_profile_dump(verbose);
999 ret = ok ? 0 : 1;
1000 goto done;
1001 case 'R':
1002 /* Continuously display rate-converted data */
1003 ok = status_profile_rates(verbose);
1004 ret = ok ? 0 : 1;
1005 goto done;
1006 default:
1007 break;
1010 if ( show_processes ) {
1011 prepare_sessionid(&state);
1012 sessionid_traverse_read(traverse_sessionid, &state);
1014 if (processes_only) {
1015 goto done;
1019 if ( show_shares ) {
1020 if (brief) {
1021 goto done;
1023 prepare_connections(&state);
1024 connections_forall_read(traverse_connections, &state);
1026 d_printf("\n");
1028 if ( shares_only ) {
1029 goto done;
1033 if ( show_locks ) {
1034 int result;
1035 struct db_context *db;
1037 db_path = lock_path(talloc_tos(), "locking.tdb");
1038 if (db_path == NULL) {
1039 fprintf(stderr, "Out of memory - exiting\n");
1040 ret = -1;
1041 goto done;
1044 db = db_open(NULL, db_path, 0,
1045 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDONLY, 0,
1046 DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
1048 if (!db) {
1049 fprintf(stderr, "%s not initialised\n", db_path);
1050 fprintf(stderr, "This is normal if an SMB client has never "
1051 "connected to your server.\n");
1052 TALLOC_FREE(db_path);
1053 exit(0);
1054 } else {
1055 TALLOC_FREE(db);
1056 TALLOC_FREE(db_path);
1059 if (!locking_init_readonly()) {
1060 fprintf(stderr, "Can't initialise locking module - exiting\n");
1061 ret = 1;
1062 goto done;
1065 prepare_share_mode(&state);
1066 result = share_entry_forall(print_share_mode, &state);
1068 if (result == 0) {
1069 fprintf(stderr, "No locked files\n");
1070 } else if (result < 0) {
1071 fprintf(stderr, "locked file list truncated\n");
1074 d_printf("\n");
1076 if (show_brl) {
1077 prepare_brl(&state);
1078 brl_forall(print_brl, &state);
1081 locking_end();
1084 if (show_notify) {
1085 prepare_notify(&state);
1086 notify_walk(msg_ctx, print_notify_rec, &state);
1089 done:
1090 cmdline_messaging_context_free();
1091 poptFreeContext(pc);
1092 TALLOC_FREE(frame);
1093 return ret;