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