2 Unix SMB/CIFS implementation.
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/>.
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
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"
42 #include "locking/share_mode_lock.h"
43 #include "locking/proto.h"
45 #include "librpc/gen_ndr/open_files.h"
46 #include "smbd/smbd.h"
47 #include "librpc/gen_ndr/notify.h"
50 #include "status_profile.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
;
68 static bool numeric_only
;
69 static bool do_checks
= true;
71 const char *username
= NULL
;
74 static void Ucrit_addUid(uid_t uid
)
80 static unsigned int Ucrit_checkUid(uid_t uid
)
82 if ( !Ucrit_IsActive
)
85 if ( uid
== Ucrit_uid
)
91 static unsigned int Ucrit_checkPid(struct server_id pid
)
95 if ( !Ucrit_IsActive
)
98 for (i
=0;i
<Ucrit_MaxPid
;i
++) {
99 if (server_id_equal(&pid
, &Ucrit_pid
[i
])) {
107 static bool Ucrit_addPid( struct server_id pid
)
109 if ( !Ucrit_IsActive
)
112 if ( Ucrit_MaxPid
>= SMB_MAXPIDS
) {
113 fprintf(stderr
, "ERROR: More than %d pids for user %s!\n",
114 SMB_MAXPIDS
, uidtoname(Ucrit_uid
));
119 Ucrit_pid
[Ucrit_MaxPid
++] = pid
;
124 static int print_share_mode_stdout(struct traverse_state
*state
,
126 const char *user_name
,
127 const char *denymode
,
131 const char *servicepath
,
132 const char *filename
,
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
);
149 static int prepare_share_mode(struct traverse_state
*state
)
151 /* only print header line if there are open files */
157 static int print_share_mode(struct file_id fid
,
158 const struct share_mode_data
*d
,
159 const struct share_mode_entry
*e
,
162 const char *denymode
= NULL
;
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
) {
177 if (do_checks
&& !is_valid_share_mode_entry(e
)) {
178 TALLOC_FREE(tmp_ctx
);
182 if (do_checks
&& !serverid_exists(&e
->pid
)) {
183 /* the process for this entry does not exist any more */
184 TALLOC_FREE(tmp_ctx
);
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
));
194 user_str
= talloc_asprintf(tmp_ctx
, "%u", (unsigned int)e
->uid
);
196 if (user_str
== NULL
) {
197 TALLOC_FREE(tmp_ctx
);
201 denymode_int
= map_share_mode_to_deny_mode(e
->share_access
,
203 switch (denymode_int
) {
205 denymode
= "DENY_NONE";
208 denymode
= "DENY_ALL";
211 denymode
= "DENY_DOS";
214 denymode
= "DENY_READ";
217 denymode
= "DENY_WRITE";
220 denymode
= "DENY_FCB";
223 denymode
= talloc_asprintf(tmp_ctx
,
226 if (denymode
== NULL
) {
227 TALLOC_FREE(tmp_ctx
);
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
);
239 filename
= talloc_asprintf(tmp_ctx
,
242 (d
->stream_name
!= NULL
) ? d
->stream_name
: "");
243 if (filename
== NULL
) {
244 TALLOC_FREE(tmp_ctx
);
247 if ((e
->access_mask
& (FILE_READ_DATA
|FILE_WRITE_DATA
))==
248 (FILE_READ_DATA
|FILE_WRITE_DATA
)) {
250 } else if (e
->access_mask
& FILE_WRITE_DATA
) {
256 if (e
->op_type
& BATCH_OPLOCK
) {
258 } else if (e
->op_type
& EXCLUSIVE_OPLOCK
) {
259 oplock
= "EXCLUSIVE";
260 } else if (e
->op_type
& LEVEL_II_OPLOCK
) {
262 } else if (e
->op_type
== LEASE_OPLOCK
) {
266 status
= leases_db_get(
270 &lstate
, /* current_state */
272 NULL
, /* breaking_to_requested */
273 NULL
, /* breaking_to_required */
274 NULL
, /* lease_version */
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
)?"":" ");
286 oplock
= "LEASE STATE UNKNOWN";
292 timestr
= time_to_asc((time_t)e
->time
.tv_sec
);
293 print_share_mode_stdout(state
,
297 (unsigned int)e
->access_mask
,
304 TALLOC_FREE(tmp_ctx
);
308 static void print_brl_stdout(struct traverse_state
*state
,
314 const char *sharepath
,
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 */
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
,
345 static const struct {
346 enum brl_type lock_type
;
353 const char *desc
="X";
354 const char *sharepath
= "";
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
);
363 fname
= share_mode_filename(NULL
, share_mode
);
365 fname
= talloc_strdup(NULL
, "");
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
),
387 TALLOC_FREE(share_mode
);
390 static const char *session_dialect_str(uint16_t dialect
)
392 static fstring unknown_dialect
;
395 case SMB2_DIALECT_REVISION_000
:
397 case SMB2_DIALECT_REVISION_202
:
399 case SMB2_DIALECT_REVISION_210
:
401 case SMB2_DIALECT_REVISION_222
:
403 case SMB2_DIALECT_REVISION_224
:
405 case SMB3_DIALECT_REVISION_300
:
407 case SMB3_DIALECT_REVISION_302
:
409 case SMB3_DIALECT_REVISION_310
:
411 case SMB3_DIALECT_REVISION_311
:
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
,
424 const char *encryption
,
427 d_printf("%-12s %-7s %-13s %-32s %-12s %-12s\n",
428 servicename
, server_id
, machine
, timestr
, encryption
, signing
);
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");
442 static int traverse_connections(const struct connections_data
*crec
,
445 struct server_id_buf tmp
;
446 char *timestr
= NULL
;
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
) {
457 if (crec
->cnum
== TID_FIELD_INVALID
) {
458 TALLOC_FREE(tmp_ctx
);
463 (!process_exists(crec
->pid
) || !Ucrit_checkUid(crec
->uid
))) {
464 TALLOC_FREE(tmp_ctx
);
468 timestr
= timestring(tmp_ctx
, crec
->start
);
469 if (timestr
== NULL
) {
470 TALLOC_FREE(tmp_ctx
);
474 if (smbXsrv_is_encrypted(crec
->encryption_flags
)) {
475 switch (crec
->cipher
) {
476 case SMB_ENCRYPTION_GSSAPI
:
477 encryption
= "GSSAPI";
479 case SMB2_ENCRYPTION_AES128_CCM
:
480 encryption
= "AES-128-CCM";
482 case SMB2_ENCRYPTION_AES128_GCM
:
483 encryption
= "AES-128-GCM";
492 if (smbXsrv_is_signed(crec
->signing_flags
)) {
493 switch (crec
->signing
) {
494 case SMB2_SIGNING_MD5_SMB1
:
495 signing
= "HMAC-MD5";
497 case SMB2_SIGNING_HMAC_SHA256
:
498 signing
= "HMAC-SHA256";
500 case SMB2_SIGNING_AES128_CMAC
:
501 signing
= "AES-128-CMAC";
503 case SMB2_SIGNING_AES128_GMAC
:
504 signing
= "AES-128-GMAC";
513 result
= traverse_connections_stdout(state
,
515 server_id_str_buf(crec
->pid
, &tmp
),
521 TALLOC_FREE(timestr
);
522 TALLOC_FREE(tmp_ctx
);
527 static int traverse_sessionid_stdout(struct traverse_state
*state
,
530 char *machine_hostname
,
532 const char *encryption
,
535 d_printf("%-7s %-25s %-41s %-17s %-20s %-21s\n",
536 server_id
, uid_gid_str
, machine_hostname
, dialect
, encryption
,
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");
553 static int traverse_sessionid(const char *key
, struct sessionid
*session
,
557 struct server_id_buf tmp
;
558 char *machine_hostname
= NULL
;
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
) {
570 (!process_exists(session
->pid
) ||
571 !Ucrit_checkUid(session
->uid
))) {
572 TALLOC_FREE(tmp_ctx
);
576 Ucrit_addPid(session
->pid
);
579 fstr_sprintf(uid_gid_str
, "%-12u %-12u",
580 (unsigned int)session
->uid
,
581 (unsigned int)session
->gid
);
583 if (session
->uid
== -1 && session
->gid
== -1) {
585 * The session is not fully authenticated yet.
587 fstrcpy(uid_gid_str
, "(auth in progress)");
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
);
605 if (session
->gid
!= -1) {
606 gid_name
= gidtoname(session
->gid
);
607 if (gid_name
== NULL
) {
608 TALLOC_FREE(tmp_ctx
);
612 fstr_sprintf(uid_gid_str
, "%-12s %-12s",
617 machine_hostname
= talloc_asprintf(tmp_ctx
, "%s (%s)",
618 session
->remote_machine
,
620 if (machine_hostname
== NULL
) {
621 TALLOC_FREE(tmp_ctx
);
625 if (smbXsrv_is_encrypted(session
->encryption_flags
)) {
626 switch (session
->cipher
) {
627 case SMB2_ENCRYPTION_AES128_CCM
:
628 encryption
= "AES-128-CCM";
630 case SMB2_ENCRYPTION_AES128_GCM
:
631 encryption
= "AES-128-GCM";
633 case SMB2_ENCRYPTION_AES256_CCM
:
634 encryption
= "AES-256-CCM";
636 case SMB2_ENCRYPTION_AES256_GCM
:
637 encryption
= "AES-256-GCM";
644 } else if (smbXsrv_is_partially_encrypted(session
->encryption_flags
)) {
645 switch (session
->cipher
) {
646 case SMB_ENCRYPTION_GSSAPI
:
647 encryption
= "partial(GSSAPI)";
649 case SMB2_ENCRYPTION_AES128_CCM
:
650 encryption
= "partial(AES-128-CCM)";
652 case SMB2_ENCRYPTION_AES128_GCM
:
653 encryption
= "partial(AES-128-GCM)";
655 case SMB2_ENCRYPTION_AES256_CCM
:
656 encryption
= "partial(AES-256-CCM)";
658 case SMB2_ENCRYPTION_AES256_GCM
:
659 encryption
= "partial(AES-256-GCM)";
668 if (smbXsrv_is_signed(session
->signing_flags
)) {
669 switch (session
->signing
) {
670 case SMB2_SIGNING_MD5_SMB1
:
671 signing
= "HMAC-MD5";
673 case SMB2_SIGNING_HMAC_SHA256
:
674 signing
= "HMAC-SHA256";
676 case SMB2_SIGNING_AES128_CMAC
:
677 signing
= "AES-128-CMAC";
679 case SMB2_SIGNING_AES128_GMAC
:
680 signing
= "AES-128-GMAC";
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)";
692 case SMB2_SIGNING_HMAC_SHA256
:
693 signing
= "partial(HMAC-SHA256)";
695 case SMB2_SIGNING_AES128_CMAC
:
696 signing
= "partial(AES-128-CMAC)";
698 case SMB2_SIGNING_AES128_GMAC
:
699 signing
= "partial(AES-128-GMAC)";
709 traverse_sessionid_stdout(state
,
710 server_id_str_buf(session
->pid
, &tmp
),
713 session_dialect_str(session
->connection_dialect
),
717 TALLOC_FREE(machine_hostname
);
718 TALLOC_FREE(tmp_ctx
);
724 static bool print_notify_rec_stdout(struct traverse_state
*state
,
728 unsigned subdir_filter
)
730 d_printf("%s\\%s\\%x\\%x\n", path
, server_id_str
,
731 filter
, subdir_filter
);
736 static int prepare_notify(struct traverse_state
*state
)
738 /* don't print header line */
743 static bool print_notify_rec(const char *path
, struct server_id server
,
744 const struct notify_instance
*instance
,
747 struct server_id_buf idbuf
;
748 struct traverse_state
*state
= (struct traverse_state
*)private_data
;
751 result
= print_notify_rec_stdout(state
,
753 server_id_str_buf(server
, &idbuf
),
754 (unsigned)instance
->filter
,
755 (unsigned)instance
->subdir_filter
);
761 OPT_RESOLVE_UIDS
= 1000,
764 int main(int argc
, const char *argv
[])
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
[] = {
775 .longName
= "processes",
777 .argInfo
= POPT_ARG_NONE
,
780 .descrip
= "Show processes only",
783 .longName
= "verbose",
785 .argInfo
= POPT_ARG_NONE
,
788 .descrip
= "Be verbose",
793 .argInfo
= POPT_ARG_NONE
,
796 .descrip
= "Show locks only",
799 .longName
= "shares",
801 .argInfo
= POPT_ARG_NONE
,
804 .descrip
= "Show shares only",
807 .longName
= "notify",
809 .argInfo
= POPT_ARG_NONE
,
812 .descrip
= "Show notifies",
817 .argInfo
= POPT_ARG_STRING
,
820 .descrip
= "Switch to user",
825 .argInfo
= POPT_ARG_NONE
,
828 .descrip
= "Be brief",
831 .longName
= "profile",
833 .argInfo
= POPT_ARG_NONE
,
836 .descrip
= "Do profiling",
839 .longName
= "profile-rates",
841 .argInfo
= POPT_ARG_NONE
,
844 .descrip
= "Show call rates",
847 .longName
= "byterange",
849 .argInfo
= POPT_ARG_NONE
,
852 .descrip
= "Include byte range locks"
855 .longName
= "numeric",
857 .argInfo
= POPT_ARG_NONE
,
860 .descrip
= "Numeric uid/gid"
865 .argInfo
= POPT_ARG_NONE
,
868 .descrip
= "Skip checks if processes still exist"
871 .longName
= "resolve-uids",
873 .argInfo
= POPT_ARG_NONE
,
875 .val
= OPT_RESOLVE_UIDS
,
876 .descrip
= "Try to resolve UIDs to usernames"
882 TALLOC_CTX
*frame
= talloc_stackframe();
884 struct messaging_context
*msg_ctx
= NULL
;
889 state
.resolve_uids
= false;
893 ok
= samba_cmdline_init(frame
,
894 SAMBA_CMDLINE_CONFIG_CLIENT
,
895 false /* require_smbconf */);
897 DBG_ERR("Failed to init cmdline parser!\n");
901 lp_set_cmdline("log level", "0");
903 pc
= samba_popt_get_context(getprogname(),
907 POPT_CONTEXT_KEEP_FIRST
);
909 DBG_ERR("Failed to setup popt context!\n");
914 while ((c
= poptGetNextOpt(pc
)) != -1) {
917 processes_only
= true;
935 Ucrit_addUid(nametouid(poptGetOptArg(pc
)));
950 case OPT_RESOLVE_UIDS
:
951 state
.resolve_uids
= true;
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);
963 if (getuid() != geteuid()) {
964 fprintf(stderr
, "smbstatus should not be run setuid\n");
970 fprintf(stderr
, "smbstatus only works as root!\n");
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
;
982 Ucrit_addUid( nametouid(username
) );
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");
995 switch (profile_only
) {
997 /* Dump profile data */
998 ok
= status_profile_dump(verbose
);
1002 /* Continuously display rate-converted data */
1003 ok
= status_profile_rates(verbose
);
1010 if ( show_processes
) {
1011 prepare_sessionid(&state
);
1012 sessionid_traverse_read(traverse_sessionid
, &state
);
1014 if (processes_only
) {
1019 if ( show_shares
) {
1023 prepare_connections(&state
);
1024 connections_forall_read(traverse_connections
, &state
);
1028 if ( shares_only
) {
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");
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
);
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
);
1056 TALLOC_FREE(db_path
);
1059 if (!locking_init_readonly()) {
1060 fprintf(stderr
, "Can't initialise locking module - exiting\n");
1065 prepare_share_mode(&state
);
1066 result
= share_entry_forall(print_share_mode
, &state
);
1069 fprintf(stderr
, "No locked files\n");
1070 } else if (result
< 0) {
1071 fprintf(stderr
, "locked file list truncated\n");
1077 prepare_brl(&state
);
1078 brl_forall(print_brl
, &state
);
1085 prepare_notify(&state
);
1086 notify_walk(msg_ctx
, print_notify_rec
, &state
);
1090 cmdline_messaging_context_free();
1091 poptFreeContext(pc
);