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_noparent; 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, *nname; 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 boolean 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 nname = noname(params[i].jp_name); 148 *dot = '.'; 149 param_noparent[i] = 150 add_param(nname, NULL, (size_t)0, NULL, 151 JP_OPT); 152 free(nname); 153 } 154 } 155 } 156 157 /* Add the index key parameters. */ 158 if (jid != 0) 159 add_param("jid", &jid, sizeof(jid), NULL, 0); 160 else if (jname != NULL) 161 add_param("name", jname, strlen(jname), NULL, 0); 162 else 163 add_param("lastjid", &lastjid, sizeof(lastjid), NULL, 0); 164 165 /* Print a header line if requested. */ 166 if (pflags & PRINT_VERBOSE) 167 printf(" JID Hostname Path\n" 168 " Name State\n" 169 " CPUSetID\n" 170 " IP Address(es)\n"); 171 else if (pflags & PRINT_DEFAULT) 172 printf(" JID IP Address " 173 "Hostname Path\n"); 174 else if (pflags & PRINT_HEADER) { 175 for (i = spc = 0; i < nparams; i++) 176 if (params[i].jp_flags & JP_USER) { 177 if (spc) 178 putchar(' '); 179 else 180 spc = 1; 181 fputs(params[i].jp_name, stdout); 182 } 183 putchar('\n'); 184 } 185 186 /* Fetch the jail(s) and print the paramters. */ 187 if (jid != 0 || jname != NULL) { 188 if (print_jail(pflags, jflags) < 0) 189 errx(1, "%s", jail_errmsg); 190 } else { 191 for (lastjid = 0; 192 (lastjid = print_jail(pflags, jflags)) >= 0; ) 193 ; 194 if (errno != 0 && errno != ENOENT) 195 errx(1, "%s", jail_errmsg); 196 } 197 198 return (0); 199 } 200 201 static int 202 add_param(const char *name, void *value, size_t valuelen, 203 struct jailparam *source, unsigned flags) 204 { 205 struct jailparam *param, *tparams; 206 int i, tnparams; 207 208 static int paramlistsize; 209 210 /* The pseudo-parameter "all" scans the list of available parameters. */ 211 if (!strcmp(name, "all")) { 212 tnparams = jailparam_all(&tparams); 213 if (tnparams < 0) 214 errx(1, "%s", jail_errmsg); 215 qsort(tparams, (size_t)tnparams, sizeof(struct jailparam), 216 sort_param); 217 for (i = 0; i < tnparams; i++) 218 add_param(tparams[i].jp_name, NULL, (size_t)0, 219 tparams + i, flags); 220 free(tparams); 221 return -1; 222 } 223 224 /* Check for repeat parameters. */ 225 for (i = 0; i < nparams; i++) 226 if (!strcmp(name, params[i].jp_name)) { 227 if (value != NULL && jailparam_import_raw(params + i, 228 value, valuelen) < 0) 229 errx(1, "%s", jail_errmsg); 230 params[i].jp_flags |= flags; 231 if (source != NULL) 232 jailparam_free(source, 1); 233 return i; 234 } 235 236 /* Make sure there is room for the new param record. */ 237 if (!nparams) { 238 paramlistsize = 32; 239 params = malloc(paramlistsize * sizeof(*params)); 240 param_noparent = 241 malloc(paramlistsize * sizeof(*param_noparent)); 242 if (params == NULL || param_noparent == NULL) 243 err(1, "malloc"); 244 } else if (nparams >= paramlistsize) { 245 paramlistsize *= 2; 246 params = realloc(params, paramlistsize * sizeof(*params)); 247 param_noparent = realloc(param_noparent, 248 paramlistsize * sizeof(*param_noparent)); 249 if (params == NULL || param_noparent == NULL) 250 err(1, "realloc"); 251 } 252 253 /* Look up the parameter. */ 254 param_noparent[nparams] = -1; 255 param = params + nparams++; 256 if (source != NULL) { 257 *param = *source; 258 param->jp_flags |= flags; 259 return param - params; 260 } 261 if (jailparam_init(param, name) < 0) 262 errx(1, "%s", jail_errmsg); 263 param->jp_flags = flags; 264 if ((value != NULL ? jailparam_import_raw(param, value, valuelen) 265 : jailparam_import(param, value)) < 0) { 266 if (flags & JP_OPT) { 267 nparams--; 268 return (-1); 269 } 270 errx(1, "%s", jail_errmsg); 271 } 272 return param - params; 273 } 274 275 static int 276 sort_param(const void *a, const void *b) 277 { 278 const struct jailparam *parama, *paramb; 279 char *ap, *bp; 280 281 /* Put top-level parameters first. */ 282 parama = a; 283 paramb = b; 284 ap = strchr(parama->jp_name, '.'); 285 bp = strchr(paramb->jp_name, '.'); 286 if (ap && !bp) 287 return (1); 288 if (bp && !ap) 289 return (-1); 290 return (strcmp(parama->jp_name, paramb->jp_name)); 291 } 292 293 static char * 294 noname(const char *name) 295 { 296 char *nname, *p; 297 298 nname = malloc(strlen(name) + 3); 299 if (nname == NULL) 300 err(1, "malloc"); 301 p = strrchr(name, '.'); 302 if (p != NULL) 303 sprintf(nname, "%.*s.no%s", (int)(p - name), name, p + 1); 304 else 305 sprintf(nname, "no%s", name); 306 return nname; 307 } 308 309 static char * 310 nononame(const char *name) 311 { 312 char *nname, *p; 313 314 p = strrchr(name, '.'); 315 if (strncmp(p ? p + 1 : name, "no", 2)) 316 return NULL; 317 nname = malloc(strlen(name) - 1); 318 if (nname == NULL) 319 err(1, "malloc"); 320 if (p != NULL) 321 sprintf(nname, "%.*s.%s", (int)(p - name), name, p + 3); 322 else 323 strcpy(nname, name + 2); 324 return nname; 325 } 326 327 static int 328 print_jail(int pflags, int jflags) 329 { 330 char *nname; 331 char **param_values; 332 int i, ai, jid, count, spc; 333 char ipbuf[INET6_ADDRSTRLEN]; 334 335 jid = jailparam_get(params, nparams, jflags); 336 if (jid < 0) 337 return jid; 338 if (pflags & PRINT_VERBOSE) { 339 printf("%6d %-29.29s %.74s\n" 340 "%6s %-29.29s %.74s\n" 341 "%6s %-6d\n", 342 *(int *)params[0].jp_value, 343 (char *)params[1].jp_value, 344 (char *)params[2].jp_value, 345 "", 346 (char *)params[3].jp_value, 347 *(int *)params[4].jp_value ? "DYING" : "ACTIVE", 348 "", 349 *(int *)params[5].jp_value); 350 count = params[6].jp_valuelen / sizeof(struct in_addr); 351 for (ai = 0; ai < count; ai++) 352 if (inet_ntop(AF_INET, 353 &((struct in_addr *)params[6].jp_value)[ai], 354 ipbuf, sizeof(ipbuf)) == NULL) 355 err(1, "inet_ntop"); 356 else 357 printf("%6s %-15.15s\n", "", ipbuf); 358 if (!strcmp(params[7].jp_name, "ip6.addr")) { 359 count = params[7].jp_valuelen / sizeof(struct in6_addr); 360 for (ai = 0; ai < count; ai++) 361 if (inet_ntop(AF_INET6, 362 &((struct in_addr *)params[7].jp_value)[ai], 363 ipbuf, sizeof(ipbuf)) == NULL) 364 err(1, "inet_ntop"); 365 else 366 printf("%6s %-15.15s\n", "", ipbuf); 367 } 368 } else if (pflags & PRINT_DEFAULT) 369 printf("%6d %-15.15s %-29.29s %.74s\n", 370 *(int *)params[0].jp_value, 371 params[1].jp_valuelen == 0 ? "-" 372 : inet_ntoa(*(struct in_addr *)params[1].jp_value), 373 (char *)params[2].jp_value, 374 (char *)params[3].jp_value); 375 else { 376 param_values = alloca(nparams * sizeof(*param_values)); 377 for (i = 0; i < nparams; i++) { 378 if (!(params[i].jp_flags & JP_USER)) 379 continue; 380 param_values[i] = jailparam_export(params + i); 381 if (param_values[i] == NULL) 382 errx(1, "%s", jail_errmsg); 383 } 384 for (i = spc = 0; i < nparams; i++) { 385 if (!(params[i].jp_flags & JP_USER)) 386 continue; 387 if ((pflags & PRINT_SKIP) && 388 ((!(params[i].jp_ctltype & 389 (CTLFLAG_WR | CTLFLAG_TUN))) || 390 (param_noparent[i] >= 0 && 391 *(int *)params[param_noparent[i]].jp_value))) 392 continue; 393 if (spc) 394 putchar(' '); 395 else 396 spc = 1; 397 if (pflags & PRINT_NAMEVAL) { 398 /* 399 * Generally "name=value", but for booleans 400 * either "name" or "noname". 401 */ 402 if (params[i].jp_flags & 403 (JP_BOOL | JP_NOBOOL)) { 404 if (*(int *)params[i].jp_value) 405 printf("%s", params[i].jp_name); 406 else { 407 nname = (params[i].jp_flags & 408 JP_NOBOOL) ? 409 nononame(params[i].jp_name) 410 : noname(params[i].jp_name); 411 printf("%s", nname); 412 free(nname); 413 } 414 continue; 415 } 416 printf("%s=", params[i].jp_name); 417 } 418 if (params[i].jp_valuelen == 0) { 419 if (pflags & PRINT_QUOTED) 420 printf("\"\""); 421 else if (!(pflags & PRINT_NAMEVAL)) 422 putchar('-'); 423 } else 424 quoted_print(param_values[i]); 425 } 426 putchar('\n'); 427 for (i = 0; i < nparams; i++) 428 if (params[i].jp_flags & JP_USER) 429 free(param_values[i]); 430 } 431 for (i = 0; i < nparams; i++) 432 if (!(params[i].jp_flags & JP_RAWVALUE)) { 433 free(params[i].jp_value); 434 params[i].jp_value = NULL; 435 } 436 return (jid); 437 } 438 439 static void 440 quoted_print(char *str) 441 { 442 int c, qc; 443 char *p = str; 444 445 /* An empty string needs quoting. */ 446 if (!*p) { 447 fputs("\"\"", stdout); 448 return; 449 } 450 451 /* 452 * The value will be surrounded by quotes if it contains spaces 453 * or quotes. 454 */ 455 qc = strchr(p, '\'') ? '"' 456 : strchr(p, '"') ? '\'' 457 : strchr(p, ' ') || strchr(p, '\t') ? '"' 458 : 0; 459 if (qc) 460 putchar(qc); 461 while ((c = *p++)) { 462 if (c == '\\' || c == qc) 463 putchar('\\'); 464 putchar(c); 465 } 466 if (qc) 467 putchar(qc); 468 } 469