Revert "lib/util: make use of tfork in samba_runcmd_send()"
[samba.git] / lib / util / server_id.c
1 /*
2    Unix SMB/CIFS implementation.
3    Samba utility functions
4    Copyright (C) Andrew Bartlett 2011
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
20 #include "replace.h"
21 #include "lib/util/debug.h"
22 #include "lib/util/fault.h"
23 #include "lib/util/server_id.h"
24 #include "lib/util/byteorder.h"
25 #include "librpc/gen_ndr/server_id.h"
26
27 bool server_id_same_process(const struct server_id *p1,
28                             const struct server_id *p2)
29 {
30         return ((p1->pid == p2->pid) && (p1->vnn == p2->vnn));
31 }
32
33 bool server_id_equal(const struct server_id *p1, const struct server_id *p2)
34 {
35         if (!server_id_same_process(p1, p2)) {
36                 return false;
37         }
38
39         if (p1->task_id != p2->task_id) {
40                 return false;
41         }
42
43         if (p1->unique_id != p2->unique_id) {
44                 return false;
45         }
46
47         return true;
48 }
49
50 char *server_id_str_buf(struct server_id id, struct server_id_buf *dst)
51 {
52         if (server_id_is_disconnected(&id)) {
53                 strlcpy(dst->buf, "disconnected", sizeof(dst->buf));
54         } else if ((id.vnn == NONCLUSTER_VNN) && (id.task_id == 0)) {
55                 snprintf(dst->buf, sizeof(dst->buf), "%llu",
56                          (unsigned long long)id.pid);
57         } else if (id.vnn == NONCLUSTER_VNN) {
58                 snprintf(dst->buf, sizeof(dst->buf), "%llu.%u",
59                          (unsigned long long)id.pid, (unsigned)id.task_id);
60         } else if (id.task_id == 0) {
61                 snprintf(dst->buf, sizeof(dst->buf), "%u:%llu",
62                          (unsigned)id.vnn, (unsigned long long)id.pid);
63         } else {
64                 snprintf(dst->buf, sizeof(dst->buf), "%u:%llu.%u",
65                          (unsigned)id.vnn,
66                          (unsigned long long)id.pid,
67                          (unsigned)id.task_id);
68         }
69         return dst->buf;
70 }
71
72 size_t server_id_str_buf_unique(struct server_id id, char *buf, size_t buflen)
73 {
74         struct server_id_buf idbuf;
75         char unique_buf[21];    /* 2^64 is 18446744073709551616, 20 chars */
76         size_t idlen, unique_len, needed;
77
78         server_id_str_buf(id, &idbuf);
79
80         idlen = strlen(idbuf.buf);
81         unique_len = snprintf(unique_buf, sizeof(unique_buf), "%"PRIu64,
82                               id.unique_id);
83         needed = idlen + unique_len + 2;
84
85         if (buflen >= needed) {
86                 memcpy(buf, idbuf.buf, idlen);
87                 buf[idlen] = '/';
88                 memcpy(buf + idlen + 1, unique_buf, unique_len+1);
89         }
90
91         return needed;
92 }
93
94 struct server_id server_id_from_string(uint32_t local_vnn,
95                                        const char *pid_string)
96 {
97         struct server_id templ = {
98                 .vnn = NONCLUSTER_VNN, .pid = UINT64_MAX
99         };
100         struct server_id result;
101         int ret;
102
103         /*
104          * We accept various forms with 1, 2 or 3 component forms
105          * because the server_id_str_buf() can print different forms, and
106          * we want backwards compatibility for scripts that may call
107          * smbclient.
108          */
109
110         result = templ;
111         ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32"/%"SCNu64,
112                      &result.vnn, &result.pid, &result.task_id,
113                      &result.unique_id);
114         if (ret == 4) {
115                 return result;
116         }
117
118         result = templ;
119         ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32,
120                      &result.vnn, &result.pid, &result.task_id);
121         if (ret == 3) {
122                 return result;
123         }
124
125         result = templ;
126         ret = sscanf(pid_string, "%"SCNu32":%"SCNu64"/%"SCNu64,
127                      &result.vnn, &result.pid, &result.unique_id);
128         if (ret == 3) {
129                 return result;
130         }
131
132         result = templ;
133         ret = sscanf(pid_string, "%"SCNu32":%"SCNu64,
134                      &result.vnn, &result.pid);
135         if (ret == 2) {
136                 return result;
137         }
138
139         result = templ;
140         ret = sscanf(pid_string, "%"SCNu64".%"SCNu32"/%"SCNu64,
141                      &result.pid, &result.task_id, &result.unique_id);
142         if (ret == 3) {
143                 result.vnn = local_vnn;
144                 return result;
145         }
146
147         result = templ;
148         ret = sscanf(pid_string, "%"SCNu64".%"SCNu32,
149                      &result.pid, &result.task_id);
150         if (ret == 2) {
151                 result.vnn = local_vnn;
152                 return result;
153         }
154
155         result = templ;
156         ret = sscanf(pid_string, "%"SCNu64"/%"SCNu64,
157                      &result.pid, &result.unique_id);
158         if (ret == 2) {
159                 result.vnn = local_vnn;
160                 return result;
161         }
162
163         result = templ;
164         ret = sscanf(pid_string, "%"SCNu64, &result.pid);
165         if (ret == 1) {
166                 result.vnn = local_vnn;
167                 return result;
168         }
169
170         if (strcmp(pid_string, "disconnected") == 0) {
171                 server_id_set_disconnected(&result);
172                 return result;
173         }
174
175         return templ;
176 }
177
178 /**
179  * Set the serverid to the special value that represents a disconnected
180  * client for (e.g.) durable handles.
181  */
182 void server_id_set_disconnected(struct server_id *id)
183 {
184         SMB_ASSERT(id != NULL);
185
186         id->pid = UINT64_MAX;
187         id->task_id = UINT32_MAX;
188         id->vnn = NONCLUSTER_VNN;
189         id->unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY;
190
191         return;
192 }
193
194 /**
195  * check whether a serverid is the special placeholder for
196  * a disconnected client
197  */
198 bool server_id_is_disconnected(const struct server_id *id)
199 {
200         struct server_id dis;
201
202         SMB_ASSERT(id != NULL);
203
204         server_id_set_disconnected(&dis);
205
206         return server_id_equal(id, &dis);
207 }
208
209 void server_id_put(uint8_t buf[SERVER_ID_BUF_LENGTH],
210                    const struct server_id id)
211 {
212         SBVAL(buf, 0,  id.pid);
213         SIVAL(buf, 8,  id.task_id);
214         SIVAL(buf, 12, id.vnn);
215         SBVAL(buf, 16, id.unique_id);
216 }
217
218 void server_id_get(struct server_id *id,
219                    const uint8_t buf[SERVER_ID_BUF_LENGTH])
220 {
221         id->pid       = BVAL(buf, 0);
222         id->task_id   = IVAL(buf, 8);
223         id->vnn       = IVAL(buf, 12);
224         id->unique_id = BVAL(buf, 16);
225 }