1 /*- 2 * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org> 3 * Copyright (c) 2008 Bjoern A. Zeeb <bz@FreeBSD.org> 4 * Copyright (c) 2009 James Gritton <jamie@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/jail.h> 34 #include <sys/socket.h> 35 #include <sys/sysctl.h> 36 37 #include <arpa/inet.h> 38 #include <netinet/in.h> 39 40 #include <err.h> 41 #include <errno.h> 42 #include <jail.h> 43 #include <limits.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 49 #define JP_USER 0x01000000 50 #define JP_OPT 0x02000000 51 52 #define PRINT_DEFAULT 0x01 53 #define PRINT_HEADER 0x02 54 #define PRINT_NAMEVAL 0x04 55 #define PRINT_QUOTED 0x08 56 #define PRINT_SKIP 0x10 57 #define PRINT_VERBOSE 0x20 58 59 static struct jailparam *params; 60 static int *param_parent; 61 static int nparams; 62 63 static int add_param(const char *name, void *value, size_t valuelen, 64 struct jailparam *source, unsigned flags); 65 static int sort_param(const void *a, const void *b); 66 static char *noname(const char *name); 67 static char *nononame(const char *name); 68 static int print_jail(int pflags, int jflags); 69 static void quoted_print(char *str); 70 71 int 72 main(int argc, char **argv) 73 { 74 char *dot, *ep, *jname; 75 int c, i, jflags, jid, lastjid, pflags, spc; 76 77 jname = NULL; 78 pflags = jflags = jid = 0; 79 while ((c = getopt(argc, argv, "adj:hnqsv")) >= 0) 80 switch (c) { 81 case 'a': 82 case 'd': 83 jflags |= JAIL_DYING; 84 break; 85 case 'j': 86 jid = strtoul(optarg, &ep, 10); 87 if (!*optarg || *ep) 88 jname = optarg; 89 break; 90 case 'h': 91 pflags = (pflags & ~(PRINT_SKIP | PRINT_VERBOSE)) | 92 PRINT_HEADER; 93 break; 94 case 'n': 95 pflags = (pflags & ~PRINT_VERBOSE) | PRINT_NAMEVAL; 96 break; 97 case 'q': 98 pflags |= PRINT_QUOTED; 99 break; 100 case 's': 101 pflags = (pflags & ~(PRINT_HEADER | PRINT_VERBOSE)) | 102 PRINT_NAMEVAL | PRINT_QUOTED | PRINT_SKIP; 103 break; 104 case 'v': 105 pflags = (pflags & 106 ~(PRINT_HEADER | PRINT_NAMEVAL | PRINT_SKIP)) | 107 PRINT_VERBOSE; 108 break; 109 default: 110 errx(1, "usage: jls [-dhnqv] [-j jail] [param ...]"); 111 } 112 113 /* Add the parameters to print. */ 114 if (optind == argc) { 115 if (pflags & (PRINT_HEADER | PRINT_NAMEVAL)) 116 add_param("all", NULL, (size_t)0, NULL, JP_USER); 117 else if (pflags & PRINT_VERBOSE) { 118 add_param("jid", NULL, (size_t)0, NULL, JP_USER); 119 add_param("host.hostname", NULL, (size_t)0, NULL, 120 JP_USER); 121 add_param("path", NULL, (size_t)0, NULL, JP_USER); 122 add_param("name", NULL, (size_t)0, NULL, JP_USER); 123 add_param("dying", NULL, (size_t)0, NULL, JP_USER); 124 add_param("cpuset.id", NULL, (size_t)0, NULL, JP_USER); 125 add_param("ip4.addr", NULL, (size_t)0, NULL, JP_USER); 126 add_param("ip6.addr", NULL, (size_t)0, NULL, 127 JP_USER | JP_OPT); 128 } else { 129 pflags |= PRINT_DEFAULT; 130 add_param("jid", NULL, (size_t)0, NULL, JP_USER); 131 add_param("ip4.addr", NULL, (size_t)0, NULL, JP_USER); 132 add_param("host.hostname", NULL, (size_t)0, NULL, 133 JP_USER); 134 add_param("path", NULL, (size_t)0, NULL, JP_USER); 135 } 136 } else 137 while (optind < argc) 138 add_param(argv[optind++], NULL, (size_t)0, NULL, 139 JP_USER); 140 141 if (pflags & PRINT_SKIP) { 142 /* Check for parameters with jailsys parents. */ 143 for (i = 0; i < nparams; i++) { 144 if ((params[i].jp_flags & JP_USER) && 145 (dot = strchr(params[i].jp_name, '.'))) { 146 *dot = 0; 147 param_parent[i] = add_param(params[i].jp_name, 148 NULL, (size_t)0, NULL, JP_OPT); 149 *dot = '.'; 150 } 151 } 152 } 153 154 /* Add the index key parameters. */ 155 if (jid != 0) 156 add_param("jid", &jid, sizeof(jid), NULL, 0); 157 else if (jname != NULL) 158 add_param("name", jname, strlen(jname), NULL, 0); 159 else 160 add_param("lastjid", &lastjid, sizeof(lastjid), NULL, 0); 161 162 /* Print a header line if requested. */ 163 if (pflags & PRINT_VERBOSE) 164 printf(" JID Hostname Path\n" 165 " Name State\n" 166 " CPUSetID\n" 167 " IP Address(es)\n"); 168 else if (pflags & PRINT_DEFAULT) 169 printf(" JID IP Address " 170 "Hostname Path\n"); 171 else if (pflags & PRINT_HEADER) { 172 for (i = spc = 0; i < nparams; i++) 173 if (params[i].jp_flags & JP_USER) { 174 if (spc) 175 putchar(' '); 176 else 177 spc = 1; 178 fputs(params[i].jp_name, stdout); 179 } 180 putchar('\n'); 181 } 182 183 /* Fetch the jail(s) and print the paramters. */ 184 if (jid != 0 || jname != NULL) { 185 if (print_jail(pflags, jflags) < 0) 186 errx(1, "%s", jail_errmsg); 187 } else { 188 for (lastjid = 0; 189 (lastjid = print_jail(pflags, jflags)) >= 0; ) 190 ; 191 if (errno != 0 && errno != ENOENT) 192 errx(1, "%s", jail_errmsg); 193 } 194 195 return (0); 196 } 197 198 static int 199 add_param(const char *name, void *value, size_t valuelen, 200 struct jailparam *source, unsigned flags) 201 { 202 struct jailparam *param, *tparams; 203 int i, tnparams; 204 205 static int paramlistsize; 206 207 /* The pseudo-parameter "all" scans the list of available parameters. */ 208 if (!strcmp(name, "all")) { 209 tnparams = jailparam_all(&tparams); 210 if (tnparams < 0) 211 errx(1, "%s", jail_errmsg); 212 qsort(tparams, (size_t)tnparams, sizeof(struct jailparam), 213 sort_param); 214 for (i = 0; i < tnparams; i++) 215 add_param(tparams[i].jp_name, NULL, (size_t)0, 216 tparams + i, flags); 217 free(tparams); 218 return -1; 219 } 220 221 /* Check for repeat parameters. */ 222 for (i = 0; i < nparams; i++) 223 if (!strcmp(name, params[i].jp_name)) { 224 if (value != NULL && jailparam_import_raw(params + i, 225 value, valuelen) < 0) 226 errx(1, "%s", jail_errmsg); 227 params[i].jp_flags |= flags; 228 if (source != NULL) 229 jailparam_free(source, 1); 230 return i; 231 } 232 233 /* Make sure there is room for the new param record. */ 234 if (!nparams) { 235 paramlistsize = 32; 236 params = malloc(paramlistsize * sizeof(*params)); 237 param_parent = malloc(paramlistsize * sizeof(*param_parent)); 238 if (params == NULL || param_parent == NULL) 239 err(1, "malloc"); 240 } else if (nparams >= paramlistsize) { 241 paramlistsize *= 2; 242 params = realloc(params, paramlistsize * sizeof(*params)); 243 param_parent = realloc(param_parent, 244 paramlistsize * sizeof(*param_parent)); 245 if (params == NULL || param_parent == NULL) 246 err(1, "realloc"); 247 } 248 249 /* Look up the parameter. */ 250 param_parent[nparams] = -1; 251 param = params + nparams++; 252 if (source != NULL) { 253 *param = *source; 254 param->jp_flags |= flags; 255 return param - params; 256 } 257 if (jailparam_init(param, name) < 0) 258 errx(1, "%s", jail_errmsg); 259 param->jp_flags = flags; 260 if ((value != NULL ? jailparam_import_raw(param, value, valuelen) 261 : jailparam_import(param, value)) < 0) { 262 if (flags & JP_OPT) { 263 nparams--; 264 return (-1); 265 } 266 errx(1, "%s", jail_errmsg); 267 } 268 return param - params; 269 } 270 271 static int 272 sort_param(const void *a, const void *b) 273 { 274 const struct jailparam *parama, *paramb; 275 char *ap, *bp; 276 277 /* Put top-level parameters first. */ 278 parama = a; 279 paramb = b; 280 ap = strchr(parama->jp_name, '.'); 281 bp = strchr(paramb->jp_name, '.'); 282 if (ap && !bp) 283 return (1); 284 if (bp && !ap) 285 return (-1); 286 return (strcmp(parama->jp_name, paramb->jp_name)); 287 } 288 289 static char * 290 noname(const char *name) 291 { 292 char *nname, *p; 293 294 nname = malloc(strlen(name) + 3); 295 if (nname == NULL) 296 err(1, "malloc"); 297 p = strrchr(name, '.'); 298 if (p != NULL) 299 sprintf(nname, "%.*s.no%s", (int)(p - name), name, p + 1); 300 else 301 sprintf(nname, "no%s", name); 302 return nname; 303 } 304 305 static char * 306 nononame(const char *name) 307 { 308 char *nname, *p; 309 310 p = strrchr(name, '.'); 311 if (strncmp(p ? p + 1 : name, "no", 2)) 312 return NULL; 313 nname = malloc(strlen(name) - 1); 314 if (nname == NULL) 315 err(1, "malloc"); 316 if (p != NULL) 317 sprintf(nname, "%.*s.%s", (int)(p - name), name, p + 3); 318 else 319 strcpy(nname, name + 2); 320 return nname; 321 } 322 323 static int 324 print_jail(int pflags, int jflags) 325 { 326 char *nname; 327 char **param_values; 328 int i, ai, jid, count, spc; 329 char ipbuf[INET6_ADDRSTRLEN]; 330 331 jid = jailparam_get(params, nparams, jflags); 332 if (jid < 0) 333 return jid; 334 if (pflags & PRINT_VERBOSE) { 335 printf("%6d %-29.29s %.74s\n" 336 "%6s %-29.29s %.74s\n" 337 "%6s %-6d\n", 338 *(int *)params[0].jp_value, 339 (char *)params[1].jp_value, 340 (char *)params[2].jp_value, 341 "", 342 (char *)params[3].jp_value, 343 *(int *)params[4].jp_value ? "DYING" : "ACTIVE", 344 "", 345 *(int *)params[5].jp_value); 346 count = params[6].jp_valuelen / sizeof(struct in_addr); 347 for (ai = 0; ai < count; ai++) 348 if (inet_ntop(AF_INET, 349 &((struct in_addr *)params[6].jp_value)[ai], 350 ipbuf, sizeof(ipbuf)) == NULL) 351 err(1, "inet_ntop"); 352 else 353 printf("%6s %-15.15s\n", "", ipbuf); 354 if (!strcmp(params[7].jp_name, "ip6.addr")) { 355 count = params[7].jp_valuelen / sizeof(struct in6_addr); 356 for (ai = 0; ai < count; ai++) 357 if (inet_ntop(AF_INET6, 358 &((struct in_addr *)params[7].jp_value)[ai], 359 ipbuf, sizeof(ipbuf)) == NULL) 360 err(1, "inet_ntop"); 361 else 362 printf("%6s %s\n", "", ipbuf); 363 } 364 } else if (pflags & PRINT_DEFAULT) 365 printf("%6d %-15.15s %-29.29s %.74s\n", 366 *(int *)params[0].jp_value, 367 params[1].jp_valuelen == 0 ? "-" 368 : inet_ntoa(*(struct in_addr *)params[1].jp_value), 369 (char *)params[2].jp_value, 370 (char *)params[3].jp_value); 371 else { 372 param_values = alloca(nparams * sizeof(*param_values)); 373 for (i = 0; i < nparams; i++) { 374 if (!(params[i].jp_flags & JP_USER)) 375 continue; 376 param_values[i] = jailparam_export(params + i); 377 if (param_values[i] == NULL) 378 errx(1, "%s", jail_errmsg); 379 } 380 for (i = spc = 0; i < nparams; i++) { 381 if (!(params[i].jp_flags & JP_USER)) 382 continue; 383 if ((pflags & PRINT_SKIP) && 384 ((!(params[i].jp_ctltype & 385 (CTLFLAG_WR | CTLFLAG_TUN))) || 386 (param_parent[i] >= 0 && 387 *(int *)params[param_parent[i]].jp_value != 388 JAIL_SYS_NEW))) 389 continue; 390 if (spc) 391 putchar(' '); 392 else 393 spc = 1; 394 if (pflags & PRINT_NAMEVAL) { 395 /* 396 * Generally "name=value", but for booleans 397 * either "name" or "noname". 398 */ 399 if (params[i].jp_flags & 400 (JP_BOOL | JP_NOBOOL)) { 401 if (*(int *)params[i].jp_value) 402 printf("%s", params[i].jp_name); 403 else { 404 nname = (params[i].jp_flags & 405 JP_NOBOOL) ? 406 nononame(params[i].jp_name) 407 : noname(params[i].jp_name); 408 printf("%s", nname); 409 free(nname); 410 } 411 continue; 412 } 413 printf("%s=", params[i].jp_name); 414 } 415 if (params[i].jp_valuelen == 0) { 416 if (pflags & PRINT_QUOTED) 417 printf("\"\""); 418 else if (!(pflags & PRINT_NAMEVAL)) 419 putchar('-'); 420 } else 421 quoted_print(param_values[i]); 422 } 423 putchar('\n'); 424 for (i = 0; i < nparams; i++) 425 if (params[i].jp_flags & JP_USER) 426 free(param_values[i]); 427 } 428 for (i = 0; i < nparams; i++) 429 if (!(params[i].jp_flags & JP_RAWVALUE)) { 430 free(params[i].jp_value); 431 params[i].jp_value = NULL; 432 } 433 return (jid); 434 } 435 436 static void 437 quoted_print(char *str) 438 { 439 int c, qc; 440 char *p = str; 441 442 /* An empty string needs quoting. */ 443 if (!*p) { 444 fputs("\"\"", stdout); 445 return; 446 } 447 448 /* 449 * The value will be surrounded by quotes if it contains spaces 450 * or quotes. 451 */ 452 qc = strchr(p, '\'') ? '"' 453 : strchr(p, '"') ? '\'' 454 : strchr(p, ' ') || strchr(p, '\t') ? '"' 455 : 0; 456 if (qc) 457 putchar(qc); 458 while ((c = *p++)) { 459 if (c == '\\' || c == qc) 460 putchar('\\'); 461 putchar(c); 462 } 463 if (qc) 464 putchar(qc); 465 } 466