net: Make "net status" use functable3
[ira/wip.git] / source3 / utils / net_status.c
1 /*
2    Samba Unix/Linux SMB client library
3    net status command -- possible replacement for smbstatus
4    Copyright (C) 2003 Volker Lendecke (vl@samba.org)
5
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.
10
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.
15
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/>.  */
18
19 #include "includes.h"
20 #include "utils/net.h"
21
22 int net_status_usage(struct net_context *c, int argc, const char **argv)
23 {
24         d_printf("  net status sessions [parseable] "
25                  "Show list of open sessions\n");
26         d_printf("  net status shares [parseable]   "
27                  "Show list of open shares\n");
28         return -1;
29 }
30
31 static int show_session(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
32                         void *state)
33 {
34         bool *parseable = (bool *)state;
35         struct sessionid sessionid;
36
37         if (dbuf.dsize != sizeof(sessionid))
38                 return 0;
39
40         memcpy(&sessionid, dbuf.dptr, sizeof(sessionid));
41
42         if (!process_exists(sessionid.pid)) {
43                 return 0;
44         }
45
46         if (*parseable) {
47                 d_printf("%s\\%s\\%s\\%s\\%s\n",
48                          procid_str_static(&sessionid.pid), uidtoname(sessionid.uid),
49                          gidtoname(sessionid.gid),
50                          sessionid.remote_machine, sessionid.hostname);
51         } else {
52                 d_printf("%7s   %-12s  %-12s  %-12s (%s)\n",
53                          procid_str_static(&sessionid.pid), uidtoname(sessionid.uid),
54                          gidtoname(sessionid.gid),
55                          sessionid.remote_machine, sessionid.hostname);
56         }
57
58         return 0;
59 }
60
61 static int net_status_sessions(struct net_context *c, int argc, const char **argv)
62 {
63         TDB_CONTEXT *tdb;
64         bool parseable;
65
66         if (c->display_usage) {
67                 d_printf("Usage:\n"
68                          "net status sessions [parseable]\n"
69                          "    Display open user sessions.\n"
70                          "    If parseable is specified, output is machine-"
71                          "readable.\n");
72                 return 0;
73         }
74
75         if (argc == 0) {
76                 parseable = false;
77         } else if ((argc == 1) && strequal(argv[0], "parseable")) {
78                 parseable = true;
79         } else {
80                 return net_status_usage(c, argc, argv);
81         }
82
83         if (!parseable) {
84                 d_printf("PID     Username      Group         Machine"
85                          "                        \n");
86                 d_printf("-------------------------------------------"
87                          "------------------------\n");
88         }
89
90         tdb = tdb_open_log(lock_path("sessionid.tdb"), 0,
91                            TDB_DEFAULT, O_RDONLY, 0);
92
93         if (tdb == NULL) {
94                 d_fprintf(stderr, "%s not initialised\n", lock_path("sessionid.tdb"));
95                 return -1;
96         }
97
98         tdb_traverse(tdb, show_session, &parseable);
99         tdb_close(tdb);
100
101         return 0;
102 }
103
104 static int show_share(struct db_record *rec,
105                       const struct connections_key *key,
106                       const struct connections_data *crec,
107                       void *state)
108 {
109         if (crec->cnum == -1)
110                 return 0;
111
112         if (!process_exists(crec->pid)) {
113                 return 0;
114         }
115
116         d_printf("%-10.10s   %s   %-12s  %s",
117                crec->servicename, procid_str_static(&crec->pid),
118                crec->machine,
119                time_to_asc(crec->start));
120
121         return 0;
122 }
123
124 struct sessionids {
125         int num_entries;
126         struct sessionid *entries;
127 };
128
129 static int collect_pid(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
130                        void *state)
131 {
132         struct sessionids *ids = (struct sessionids *)state;
133         struct sessionid sessionid;
134
135         if (dbuf.dsize != sizeof(sessionid))
136                 return 0;
137
138         memcpy(&sessionid, dbuf.dptr, sizeof(sessionid));
139
140         if (!process_exists(sessionid.pid))
141                 return 0;
142
143         ids->num_entries += 1;
144         ids->entries = SMB_REALLOC_ARRAY(ids->entries, struct sessionid, ids->num_entries);
145         if (!ids->entries) {
146                 ids->num_entries = 0;
147                 return 0;
148         }
149         ids->entries[ids->num_entries-1] = sessionid;
150
151         return 0;
152 }
153
154 static int show_share_parseable(struct db_record *rec,
155                                 const struct connections_key *key,
156                                 const struct connections_data *crec,
157                                 void *state)
158 {
159         struct sessionids *ids = (struct sessionids *)state;
160         int i;
161         bool guest = true;
162
163         if (crec->cnum == -1)
164                 return 0;
165
166         if (!process_exists(crec->pid)) {
167                 return 0;
168         }
169
170         for (i=0; i<ids->num_entries; i++) {
171                 struct server_id id = ids->entries[i].pid;
172                 if (procid_equal(&id, &crec->pid)) {
173                         guest = false;
174                         break;
175                 }
176         }
177
178         d_printf("%s\\%s\\%s\\%s\\%s\\%s\\%s",
179                  crec->servicename,procid_str_static(&crec->pid),
180                  guest ? "" : uidtoname(ids->entries[i].uid),
181                  guest ? "" : gidtoname(ids->entries[i].gid),
182                  crec->machine,
183                  guest ? "" : ids->entries[i].hostname,
184                  time_to_asc(crec->start));
185
186         return 0;
187 }
188
189 static int net_status_shares_parseable(struct net_context *c, int argc, const char **argv)
190 {
191         struct sessionids ids;
192         TDB_CONTEXT *tdb;
193
194         ids.num_entries = 0;
195         ids.entries = NULL;
196
197         tdb = tdb_open_log(lock_path("sessionid.tdb"), 0,
198                            TDB_DEFAULT, O_RDONLY, 0);
199
200         if (tdb == NULL) {
201                 d_fprintf(stderr, "%s not initialised\n", lock_path("sessionid.tdb"));
202                 return -1;
203         }
204
205         tdb_traverse(tdb, collect_pid, &ids);
206         tdb_close(tdb);
207
208         connections_forall(show_share_parseable, &ids);
209
210         SAFE_FREE(ids.entries);
211
212         return 0;
213 }
214
215 static int net_status_shares(struct net_context *c, int argc, const char **argv)
216 {
217         if (c->display_usage) {
218                 d_printf("Usage:\n"
219                          "net status shares [parseable]\n"
220                          "    Display open user shares.\n"
221                          "    If parseable is specified, output is machine-"
222                          "readable.\n");
223                 return 0;
224         }
225
226         if (argc == 0) {
227
228                 d_printf("\nService      pid     machine       "
229                          "Connected at\n");
230                 d_printf("-------------------------------------"
231                          "------------------\n");
232
233                 connections_forall(show_share, NULL);
234
235                 return 0;
236         }
237
238         if ((argc != 1) || !strequal(argv[0], "parseable")) {
239                 return net_status_usage(c, argc, argv);
240         }
241
242         return net_status_shares_parseable(c, argc, argv);
243 }
244
245 int net_status(struct net_context *c, int argc, const char **argv)
246 {
247         struct functable3 func[] = {
248                 {
249                         "sessions",
250                         net_status_sessions,
251                         NET_TRANSPORT_LOCAL,
252                         "Show list of open sessions",
253                         "net status sessions [parseable]\n"
254                         "    If parseable is specified, output is presented "
255                         "in a machine-parseable fashion."
256                 },
257                 {
258                         "shares",
259                         net_status_shares,
260                         NET_TRANSPORT_LOCAL,
261                         "Show list of open shares",
262                         "net status shares [parseable]\n"
263                         "    If parseable is specified, output is presented "
264                         "in a machine-parseable fashion."
265                 },
266                 {NULL, NULL, 0, NULL, NULL}
267         };
268         return net_run_function3(c, argc, argv, "net status", func);
269 }