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_HEADER; 92 break; 93 case 'n': 94 pflags = (pflags & ~PRINT_VERBOSE) | PRINT_NAMEVAL; 95 break; 96 case 'q': 97 pflags |= PRINT_QUOTED; 98 break; 99 case 's': 100 pflags = (pflags & ~(PRINT_HEADER | PRINT_VERBOSE)) | 101 PRINT_NAMEVAL | PRINT_QUOTED | PRINT_SKIP; 102 break; 103 case 'v': 104 pflags = (pflags & ~(PRINT_NAMEVAL | PRINT_SKIP)) | 105 PRINT_VERBOSE; 106 break; 107 default: 108 errx(1, "usage: jls [-dhnqv] [-j jail] [param ...]"); 109 } 110 111 /* Add the parameters to print. */ 112 if (optind == argc) { 113 if (pflags & PRINT_VERBOSE) { 114 add_param("jid", NULL, (size_t)0, NULL, JP_USER); 115 add_param("host.hostname", NULL, (size_t)0, NULL, 116 JP_USER); 117 add_param("path", NULL, (size_t)0, NULL, JP_USER); 118 add_param("name", NULL, (size_t)0, NULL, JP_USER); 119 add_param("dying", NULL, (size_t)0, NULL, JP_USER); 120 add_param("cpuset.id", NULL, (size_t)0, NULL, JP_USER); 121 add_param("ip4.addr", NULL, (size_t)0, NULL, JP_USER); 122 add_param("ip6.addr", NULL, (size_t)0, NULL, 123 JP_USER | JP_OPT); 124 } else { 125 pflags = (pflags & 126 ~(PRINT_NAMEVAL | PRINT_SKIP | PRINT_VERBOSE)) | 127 PRINT_DEFAULT; 128 add_param("jid", NULL, (size_t)0, NULL, JP_USER); 129 add_param("ip4.addr", NULL, (size_t)0, NULL, JP_USER); 130 add_param("host.hostname", NULL, (size_t)0, NULL, 131 JP_USER); 132 add_param("path", NULL, (size_t)0, NULL, JP_USER); 133 } 134 } else 135 while (optind < argc) 136 add_param(argv[optind++], NULL, (size_t)0, NULL, 137 JP_USER); 138 139 if (pflags & PRINT_SKIP) { 140 /* Check for parameters with boolean parents. */ 141 for (i = 0; i < nparams; i++) { 142 if ((params[i].jp_flags & JP_USER) && 143 (dot = strchr(params[i].jp_name, '.'))) { 144 *dot = 0; 145 nname = noname(params[i].jp_name); 146 *dot = '.'; 147 param_noparent[i] = 148 add_param(nname, NULL, (size_t)0, NULL, 149 JP_OPT); 150 free(nname); 151 } 152 } 153 } 154 155 /* Add the index key parameters. */ 156 if (jid != 0) 157 add_param("jid", &jid, sizeof(jid), NULL, 0); 158 else if (jname != NULL) 159 add_param("name", jname, strlen(jname), NULL, 0); 160 else 161 add_param("lastjid", &lastjid, sizeof(lastjid), NULL, 0); 162 163 /* Print a header line if requested. */ 164 if (pflags & PRINT_VERBOSE) 165 printf(" JID Hostname Path\n" 166 " Name State\n" 167 " CPUSetID\n" 168 " IP Address(es)\n"); 169 else if (pflags & PRINT_DEFAULT) 170 printf(" JID IP Address " 171 "Hostname Path\n"); 172 else if (pflags & PRINT_HEADER) { 173 for (i = spc = 0; i < nparams; i++) 174 if (params[i].jp_flags & JP_USER) { 175 if (spc) 176 putchar(' '); 177 else 178 spc = 1; 179 fputs(params[i].jp_name, stdout); 180 } 181 putchar('\n'); 182 } 183 184 /* Fetch the jail(s) and print the paramters. */ 185 if (jid != 0 || jname != NULL) { 186 if (print_jail(pflags, jflags) < 0) 187 errx(1, "%s", jail_errmsg); 188 } else { 189 for (lastjid = 0; 190 (lastjid = print_jail(pflags, jflags)) >= 0; ) 191 ; 192 if (errno != 0 && errno != ENOENT) 193 errx(1, "%s", jail_errmsg); 194 } 195 196 return (0); 197 } 198 199 static int 200 add_param(const char *name, void *value, size_t valuelen, 201 struct jailparam *source, unsigned flags) 202 { 203 struct jailparam *param, *tparams; 204 int i, tnparams; 205 206 static int paramlistsize; 207 208 /* The pseudo-parameter "all" scans the list of available parameters. */ 209 if (!strcmp(name, "all")) { 210 tnparams = jailparam_all(&tparams); 211 if (tnparams < 0) 212 errx(1, "%s", jail_errmsg); 213 qsort(tparams, (size_t)tnparams, sizeof(struct jailparam), 214 sort_param); 215 for (i = 0; i < tnparams; i++) 216 add_param(tparams[i].jp_name, NULL, (size_t)0, 217 tparams + i, flags); 218 free(tparams); 219 return -1; 220 } 221 222 /* Check for repeat parameters. */ 223 for (i = 0; i < nparams; i++) 224 if (!strcmp(name, params[i].jp_name)) { 225 if (value != NULL && jailparam_import_raw(params + i, 226 value, valuelen) < 0) 227 errx(1, "%s", jail_errmsg); 228 params[i].jp_flags |= flags; 229 if (source != NULL) 230 jailparam_free(source, 1); 231 return i; 232 } 233 234 /* Make sure there is room for the new param record. */ 235 if (!nparams) { 236 paramlistsize = 32; 237 params = malloc(paramlistsize * sizeof(*params)); 238 param_noparent = 239 malloc(paramlistsize * sizeof(*param_noparent)); 240 if (params == NULL || param_noparent == NULL) 241 err(1, "malloc"); 242 } else if (nparams >= paramlistsize) { 243 paramlistsize *= 2; 244 params = realloc(params, paramlistsize * sizeof(*params)); 245 param_noparent = realloc(param_noparent, 246 paramlistsize * sizeof(*param_noparent)); 247 if (params == NULL || param_noparent == NULL) 248 err(1, "realloc"); 249 } 250 251 /* Look up the parameter. */ 252 param_noparent[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 in_addr *)params[7].jp_value)[ai], 361 ipbuf, sizeof(ipbuf)) == NULL) 362 err(1, "inet_ntop"); 363 else 364 printf("%6s %-15.15s\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_noparent[i] >= 0 && 389 *(int *)params[param_noparent[i]].jp_value))) 390 continue; 391 if (spc) 392 putchar(' '); 393 else 394 spc = 1; 395 if (pflags & PRINT_NAMEVAL) { 396 /* 397 * Generally "name=value", but for booleans 398 * either "name" or "noname". 399 */ 400 if (params[i].jp_flags & 401 (JP_BOOL | JP_NOBOOL)) { 402 if (*(int *)params[i].jp_value) 403 printf("%s", params[i].jp_name); 404 else { 405 nname = (params[i].jp_flags & 406 JP_NOBOOL) ? 407 nononame(params[i].jp_name) 408 : noname(params[i].jp_name); 409 printf("%s", nname); 410 free(nname); 411 } 412 continue; 413 } 414 printf("%s=", params[i].jp_name); 415 } 416 if (params[i].jp_valuelen == 0) { 417 if (pflags & PRINT_QUOTED) 418 printf("\"\""); 419 else if (!(pflags & PRINT_NAMEVAL)) 420 putchar('-'); 421 } else 422 quoted_print(param_values[i]); 423 } 424 putchar('\n'); 425 for (i = 0; i < nparams; i++) 426 if (params[i].jp_flags & JP_USER) 427 free(param_values[i]); 428 } 429 for (i = 0; i < nparams; i++) 430 if (!(params[i].jp_flags & JP_RAWVALUE)) { 431 free(params[i].jp_value); 432 params[i].jp_value = NULL; 433 } 434 return (jid); 435 } 436 437 static void 438 quoted_print(char *str) 439 { 440 int c, qc; 441 char *p = str; 442 443 /* An empty string needs quoting. */ 444 if (!*p) { 445 fputs("\"\"", stdout); 446 return; 447 } 448 449 /* 450 * The value will be surrounded by quotes if it contains spaces 451 * or quotes. 452 */ 453 qc = strchr(p, '\'') ? '"' 454 : strchr(p, '"') ? '\'' 455 : strchr(p, ' ') || strchr(p, '\t') ? '"' 456 : 0; 457 if (qc) 458 putchar(qc); 459 while ((c = *p++)) { 460 if (c == '\\' || c == qc) 461 putchar('\\'); 462 putchar(c); 463 } 464 if (qc) 465 putchar(qc); 466 } 467