1113277Smike/*- 2113277Smike * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org> 3185435Sbz * Copyright (c) 2008 Bjoern A. Zeeb <bz@FreeBSD.org> 4192896Sjamie * Copyright (c) 2009 James Gritton <jamie@FreeBSD.org> 5113277Smike * All rights reserved. 6113277Smike * 7113277Smike * Redistribution and use in source and binary forms, with or without 8113277Smike * modification, are permitted provided that the following conditions 9113277Smike * are met: 10113277Smike * 1. Redistributions of source code must retain the above copyright 11113277Smike * notice, this list of conditions and the following disclaimer. 12113277Smike * 2. Redistributions in binary form must reproduce the above copyright 13113277Smike * notice, this list of conditions and the following disclaimer in the 14113277Smike * documentation and/or other materials provided with the distribution. 15113277Smike * 16113277Smike * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17113277Smike * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18113277Smike * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19113277Smike * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20113277Smike * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21113277Smike * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22113277Smike * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23113277Smike * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24113277Smike * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25113277Smike * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26113277Smike * SUCH DAMAGE. 27113277Smike */ 28113277Smike 29192896Sjamie#include <sys/cdefs.h> 30192896Sjamie__FBSDID("$FreeBSD$"); 31192896Sjamie 32113277Smike#include <sys/param.h> 33113277Smike#include <sys/jail.h> 34192896Sjamie#include <sys/socket.h> 35113277Smike#include <sys/sysctl.h> 36113277Smike 37192896Sjamie#include <arpa/inet.h> 38185435Sbz#include <netinet/in.h> 39192896Sjamie 40113277Smike#include <err.h> 41113277Smike#include <errno.h> 42194869Sjamie#include <jail.h> 43113277Smike#include <limits.h> 44113277Smike#include <stdio.h> 45113277Smike#include <stdlib.h> 46185435Sbz#include <string.h> 47185435Sbz#include <unistd.h> 48113277Smike 49194869Sjamie#define JP_USER 0x01000000 50194869Sjamie#define JP_OPT 0x02000000 51113277Smike 52192896Sjamie#define PRINT_DEFAULT 0x01 53192896Sjamie#define PRINT_HEADER 0x02 54192896Sjamie#define PRINT_NAMEVAL 0x04 55192896Sjamie#define PRINT_QUOTED 0x08 56192896Sjamie#define PRINT_SKIP 0x10 57192896Sjamie#define PRINT_VERBOSE 0x20 58250736Sdes#define PRINT_JAIL_NAME 0x40 59192896Sjamie 60194869Sjamiestatic struct jailparam *params; 61195870Sjamiestatic int *param_parent; 62192896Sjamiestatic int nparams; 63222465Sbz#ifdef INET6 64222465Sbzstatic int ip6_ok; 65222465Sbz#endif 66222465Sbz#ifdef INET 67222465Sbzstatic int ip4_ok; 68222465Sbz#endif 69192896Sjamie 70194869Sjamiestatic int add_param(const char *name, void *value, size_t valuelen, 71194869Sjamie struct jailparam *source, unsigned flags); 72192896Sjamiestatic int sort_param(const void *a, const void *b); 73192896Sjamiestatic char *noname(const char *name); 74192896Sjamiestatic char *nononame(const char *name); 75192896Sjamiestatic int print_jail(int pflags, int jflags); 76194869Sjamiestatic void quoted_print(char *str); 77192896Sjamie 78192896Sjamieint 79192896Sjamiemain(int argc, char **argv) 80185435Sbz{ 81279348Sjamie char *dot, *ep, *jname, *pname; 82192896Sjamie int c, i, jflags, jid, lastjid, pflags, spc; 83185435Sbz 84192896Sjamie jname = NULL; 85192896Sjamie pflags = jflags = jid = 0; 86250736Sdes while ((c = getopt(argc, argv, "adj:hNnqsv")) >= 0) 87192896Sjamie switch (c) { 88192896Sjamie case 'a': 89192896Sjamie case 'd': 90192896Sjamie jflags |= JAIL_DYING; 91192896Sjamie break; 92192896Sjamie case 'j': 93192896Sjamie jid = strtoul(optarg, &ep, 10); 94209820Sjamie if (!jid || *ep) { 95209820Sjamie jid = 0; 96192896Sjamie jname = optarg; 97209820Sjamie } 98192896Sjamie break; 99192896Sjamie case 'h': 100195462Sjamie pflags = (pflags & ~(PRINT_SKIP | PRINT_VERBOSE)) | 101195462Sjamie PRINT_HEADER; 102192896Sjamie break; 103250736Sdes case 'N': 104250736Sdes pflags |= PRINT_JAIL_NAME; 105250736Sdes break; 106192896Sjamie case 'n': 107192896Sjamie pflags = (pflags & ~PRINT_VERBOSE) | PRINT_NAMEVAL; 108192896Sjamie break; 109192896Sjamie case 'q': 110192896Sjamie pflags |= PRINT_QUOTED; 111192896Sjamie break; 112192896Sjamie case 's': 113192896Sjamie pflags = (pflags & ~(PRINT_HEADER | PRINT_VERBOSE)) | 114192896Sjamie PRINT_NAMEVAL | PRINT_QUOTED | PRINT_SKIP; 115192896Sjamie break; 116192896Sjamie case 'v': 117195462Sjamie pflags = (pflags & 118195462Sjamie ~(PRINT_HEADER | PRINT_NAMEVAL | PRINT_SKIP)) | 119192896Sjamie PRINT_VERBOSE; 120192896Sjamie break; 121192896Sjamie default: 122250736Sdes errx(1, "usage: jls [-dhNnqv] [-j jail] [param ...]"); 123192896Sjamie } 124185435Sbz 125222465Sbz#ifdef INET6 126222465Sbz ip6_ok = feature_present("inet6"); 127222465Sbz#endif 128222465Sbz#ifdef INET 129222465Sbz ip4_ok = feature_present("inet"); 130222465Sbz#endif 131222465Sbz 132192896Sjamie /* Add the parameters to print. */ 133192896Sjamie if (optind == argc) { 134195462Sjamie if (pflags & (PRINT_HEADER | PRINT_NAMEVAL)) 135195462Sjamie add_param("all", NULL, (size_t)0, NULL, JP_USER); 136195462Sjamie else if (pflags & PRINT_VERBOSE) { 137194869Sjamie add_param("jid", NULL, (size_t)0, NULL, JP_USER); 138194869Sjamie add_param("host.hostname", NULL, (size_t)0, NULL, 139194869Sjamie JP_USER); 140194869Sjamie add_param("path", NULL, (size_t)0, NULL, JP_USER); 141194869Sjamie add_param("name", NULL, (size_t)0, NULL, JP_USER); 142194869Sjamie add_param("dying", NULL, (size_t)0, NULL, JP_USER); 143194869Sjamie add_param("cpuset.id", NULL, (size_t)0, NULL, JP_USER); 144222465Sbz#ifdef INET 145222465Sbz if (ip4_ok) 146222465Sbz add_param("ip4.addr", NULL, (size_t)0, NULL, 147222465Sbz JP_USER); 148222465Sbz#endif 149222465Sbz#ifdef INET6 150222465Sbz if (ip6_ok) 151222465Sbz add_param("ip6.addr", NULL, (size_t)0, NULL, 152222465Sbz JP_USER | JP_OPT); 153222465Sbz#endif 154192896Sjamie } else { 155195462Sjamie pflags |= PRINT_DEFAULT; 156250736Sdes if (pflags & PRINT_JAIL_NAME) 157250736Sdes add_param("name", NULL, (size_t)0, NULL, JP_USER); 158250736Sdes else 159250736Sdes add_param("jid", NULL, (size_t)0, NULL, JP_USER); 160222465Sbz#ifdef INET 161222465Sbz if (ip4_ok) 162222465Sbz add_param("ip4.addr", NULL, (size_t)0, NULL, 163222465Sbz JP_USER); 164222465Sbz#endif 165194869Sjamie add_param("host.hostname", NULL, (size_t)0, NULL, 166194869Sjamie JP_USER); 167194869Sjamie add_param("path", NULL, (size_t)0, NULL, JP_USER); 168192896Sjamie } 169279347Sjamie } else { 170279347Sjamie pflags &= ~PRINT_VERBOSE; 171192896Sjamie while (optind < argc) 172194869Sjamie add_param(argv[optind++], NULL, (size_t)0, NULL, 173194869Sjamie JP_USER); 174279347Sjamie } 175192896Sjamie 176192896Sjamie if (pflags & PRINT_SKIP) { 177195870Sjamie /* Check for parameters with jailsys parents. */ 178192896Sjamie for (i = 0; i < nparams; i++) { 179194869Sjamie if ((params[i].jp_flags & JP_USER) && 180194869Sjamie (dot = strchr(params[i].jp_name, '.'))) { 181279348Sjamie pname = alloca((dot - params[i].jp_name) + 1); 182279348Sjamie strlcpy(pname, params[i].jp_name, 183279348Sjamie (dot - params[i].jp_name) + 1); 184279348Sjamie param_parent[i] = add_param(pname, 185195870Sjamie NULL, (size_t)0, NULL, JP_OPT); 186192896Sjamie } 187192896Sjamie } 188192896Sjamie } 189192896Sjamie 190194869Sjamie /* Add the index key parameters. */ 191192896Sjamie if (jid != 0) 192194869Sjamie add_param("jid", &jid, sizeof(jid), NULL, 0); 193192896Sjamie else if (jname != NULL) 194194869Sjamie add_param("name", jname, strlen(jname), NULL, 0); 195192896Sjamie else 196194869Sjamie add_param("lastjid", &lastjid, sizeof(lastjid), NULL, 0); 197192896Sjamie 198192896Sjamie /* Print a header line if requested. */ 199192896Sjamie if (pflags & PRINT_VERBOSE) 200192896Sjamie printf(" JID Hostname Path\n" 201192896Sjamie " Name State\n" 202192896Sjamie " CPUSetID\n" 203192896Sjamie " IP Address(es)\n"); 204192896Sjamie else if (pflags & PRINT_DEFAULT) 205250736Sdes if (pflags & PRINT_JAIL_NAME) 206250736Sdes printf(" JID IP Address " 207250736Sdes "Hostname Path\n"); 208250736Sdes else 209250736Sdes printf(" JID IP Address " 210250736Sdes "Hostname Path\n"); 211192896Sjamie else if (pflags & PRINT_HEADER) { 212192896Sjamie for (i = spc = 0; i < nparams; i++) 213194869Sjamie if (params[i].jp_flags & JP_USER) { 214192896Sjamie if (spc) 215192896Sjamie putchar(' '); 216192896Sjamie else 217192896Sjamie spc = 1; 218194869Sjamie fputs(params[i].jp_name, stdout); 219192896Sjamie } 220192896Sjamie putchar('\n'); 221192896Sjamie } 222192896Sjamie 223293290Sbdrewery /* Fetch the jail(s) and print the parameters. */ 224192896Sjamie if (jid != 0 || jname != NULL) { 225194869Sjamie if (print_jail(pflags, jflags) < 0) 226194869Sjamie errx(1, "%s", jail_errmsg); 227186085Sbz } else { 228192896Sjamie for (lastjid = 0; 229192896Sjamie (lastjid = print_jail(pflags, jflags)) >= 0; ) 230192896Sjamie ; 231194869Sjamie if (errno != 0 && errno != ENOENT) 232194869Sjamie errx(1, "%s", jail_errmsg); 233186085Sbz } 234185435Sbz 235192896Sjamie return (0); 236185435Sbz} 237185435Sbz 238192896Sjamiestatic int 239194869Sjamieadd_param(const char *name, void *value, size_t valuelen, 240194869Sjamie struct jailparam *source, unsigned flags) 241185435Sbz{ 242194869Sjamie struct jailparam *param, *tparams; 243192896Sjamie int i, tnparams; 244185435Sbz 245192896Sjamie static int paramlistsize; 246185435Sbz 247192896Sjamie /* The pseudo-parameter "all" scans the list of available parameters. */ 248192896Sjamie if (!strcmp(name, "all")) { 249194869Sjamie tnparams = jailparam_all(&tparams); 250194869Sjamie if (tnparams < 0) 251194869Sjamie errx(1, "%s", jail_errmsg); 252194869Sjamie qsort(tparams, (size_t)tnparams, sizeof(struct jailparam), 253194869Sjamie sort_param); 254194869Sjamie for (i = 0; i < tnparams; i++) 255194869Sjamie add_param(tparams[i].jp_name, NULL, (size_t)0, 256194869Sjamie tparams + i, flags); 257194869Sjamie free(tparams); 258192896Sjamie return -1; 259185435Sbz } 260185435Sbz 261192896Sjamie /* Check for repeat parameters. */ 262192896Sjamie for (i = 0; i < nparams; i++) 263194869Sjamie if (!strcmp(name, params[i].jp_name)) { 264194869Sjamie if (value != NULL && jailparam_import_raw(params + i, 265194869Sjamie value, valuelen) < 0) 266194869Sjamie errx(1, "%s", jail_errmsg); 267194869Sjamie params[i].jp_flags |= flags; 268194869Sjamie if (source != NULL) 269194869Sjamie jailparam_free(source, 1); 270192896Sjamie return i; 271192896Sjamie } 272185435Sbz 273192896Sjamie /* Make sure there is room for the new param record. */ 274192896Sjamie if (!nparams) { 275192896Sjamie paramlistsize = 32; 276192896Sjamie params = malloc(paramlistsize * sizeof(*params)); 277195870Sjamie param_parent = malloc(paramlistsize * sizeof(*param_parent)); 278195870Sjamie if (params == NULL || param_parent == NULL) 279192896Sjamie err(1, "malloc"); 280192896Sjamie } else if (nparams >= paramlistsize) { 281192896Sjamie paramlistsize *= 2; 282192896Sjamie params = realloc(params, paramlistsize * sizeof(*params)); 283195870Sjamie param_parent = realloc(param_parent, 284195870Sjamie paramlistsize * sizeof(*param_parent)); 285195870Sjamie if (params == NULL || param_parent == NULL) 286192896Sjamie err(1, "realloc"); 287192896Sjamie } 288185435Sbz 289192896Sjamie /* Look up the parameter. */ 290195870Sjamie param_parent[nparams] = -1; 291192896Sjamie param = params + nparams++; 292194869Sjamie if (source != NULL) { 293194869Sjamie *param = *source; 294194869Sjamie param->jp_flags |= flags; 295194869Sjamie return param - params; 296192896Sjamie } 297279348Sjamie if (jailparam_init(param, name) < 0 || 298279348Sjamie (value != NULL ? jailparam_import_raw(param, value, valuelen) 299194869Sjamie : jailparam_import(param, value)) < 0) { 300194869Sjamie if (flags & JP_OPT) { 301192896Sjamie nparams--; 302194869Sjamie return (-1); 303192896Sjamie } 304194869Sjamie errx(1, "%s", jail_errmsg); 305192896Sjamie } 306279348Sjamie param->jp_flags = flags; 307192896Sjamie return param - params; 308192896Sjamie} 309192896Sjamie 310192896Sjamiestatic int 311192896Sjamiesort_param(const void *a, const void *b) 312192896Sjamie{ 313194869Sjamie const struct jailparam *parama, *paramb; 314192896Sjamie char *ap, *bp; 315186085Sbz 316192896Sjamie /* Put top-level parameters first. */ 317192896Sjamie parama = a; 318192896Sjamie paramb = b; 319194869Sjamie ap = strchr(parama->jp_name, '.'); 320194869Sjamie bp = strchr(paramb->jp_name, '.'); 321192896Sjamie if (ap && !bp) 322192896Sjamie return (1); 323192896Sjamie if (bp && !ap) 324192896Sjamie return (-1); 325194869Sjamie return (strcmp(parama->jp_name, paramb->jp_name)); 326185435Sbz} 327185435Sbz 328192896Sjamiestatic char * 329192896Sjamienoname(const char *name) 330185435Sbz{ 331192896Sjamie char *nname, *p; 332185435Sbz 333192896Sjamie nname = malloc(strlen(name) + 3); 334192896Sjamie if (nname == NULL) 335192896Sjamie err(1, "malloc"); 336192896Sjamie p = strrchr(name, '.'); 337192896Sjamie if (p != NULL) 338192896Sjamie sprintf(nname, "%.*s.no%s", (int)(p - name), name, p + 1); 339192896Sjamie else 340192896Sjamie sprintf(nname, "no%s", name); 341192896Sjamie return nname; 342185435Sbz} 343185435Sbz 344192896Sjamiestatic char * 345192896Sjamienononame(const char *name) 346192896Sjamie{ 347192896Sjamie char *nname, *p; 348113277Smike 349192896Sjamie p = strrchr(name, '.'); 350192896Sjamie if (strncmp(p ? p + 1 : name, "no", 2)) 351192896Sjamie return NULL; 352192896Sjamie nname = malloc(strlen(name) - 1); 353192896Sjamie if (nname == NULL) 354192896Sjamie err(1, "malloc"); 355192896Sjamie if (p != NULL) 356192896Sjamie sprintf(nname, "%.*s.%s", (int)(p - name), name, p + 3); 357192896Sjamie else 358192896Sjamie strcpy(nname, name + 2); 359192896Sjamie return nname; 360192896Sjamie} 361185435Sbz 362192896Sjamiestatic int 363192896Sjamieprint_jail(int pflags, int jflags) 364192896Sjamie{ 365192896Sjamie char *nname; 366194869Sjamie char **param_values; 367222465Sbz int i, ai, jid, count, n, spc; 368192896Sjamie char ipbuf[INET6_ADDRSTRLEN]; 369113277Smike 370194869Sjamie jid = jailparam_get(params, nparams, jflags); 371194869Sjamie if (jid < 0) 372194869Sjamie return jid; 373192896Sjamie if (pflags & PRINT_VERBOSE) { 374192896Sjamie printf("%6d %-29.29s %.74s\n" 375192896Sjamie "%6s %-29.29s %.74s\n" 376192896Sjamie "%6s %-6d\n", 377194869Sjamie *(int *)params[0].jp_value, 378194869Sjamie (char *)params[1].jp_value, 379194869Sjamie (char *)params[2].jp_value, 380192896Sjamie "", 381194869Sjamie (char *)params[3].jp_value, 382194869Sjamie *(int *)params[4].jp_value ? "DYING" : "ACTIVE", 383192896Sjamie "", 384194869Sjamie *(int *)params[5].jp_value); 385222465Sbz n = 6; 386222465Sbz#ifdef INET 387224841Sbz if (ip4_ok && !strcmp(params[n].jp_name, "ip4.addr")) { 388222465Sbz count = params[n].jp_valuelen / sizeof(struct in_addr); 389192896Sjamie for (ai = 0; ai < count; ai++) 390222465Sbz if (inet_ntop(AF_INET, 391222465Sbz &((struct in_addr *)params[n].jp_value)[ai], 392222465Sbz ipbuf, sizeof(ipbuf)) == NULL) 393222465Sbz err(1, "inet_ntop"); 394222465Sbz else 395222465Sbz printf("%6s %-15.15s\n", "", ipbuf); 396222465Sbz n++; 397222465Sbz } 398222465Sbz#endif 399222465Sbz#ifdef INET6 400222465Sbz if (ip6_ok && !strcmp(params[n].jp_name, "ip6.addr")) { 401222465Sbz count = params[n].jp_valuelen / sizeof(struct in6_addr); 402222465Sbz for (ai = 0; ai < count; ai++) 403194869Sjamie if (inet_ntop(AF_INET6, 404222465Sbz &((struct in6_addr *) 405222465Sbz params[n].jp_value)[ai], 406192896Sjamie ipbuf, sizeof(ipbuf)) == NULL) 407192896Sjamie err(1, "inet_ntop"); 408192896Sjamie else 409196137Sbz printf("%6s %s\n", "", ipbuf); 410222465Sbz n++; 411192896Sjamie } 412222465Sbz#endif 413250736Sdes } else if (pflags & PRINT_DEFAULT) { 414250736Sdes if (pflags & PRINT_JAIL_NAME) 415250736Sdes printf(" %-15s ", (char *)params[0].jp_value); 416250736Sdes else 417250736Sdes printf("%6d ", *(int *)params[0].jp_value); 418250736Sdes printf("%-15.15s %-29.29s %.74s\n", 419222465Sbz#ifdef INET 420222465Sbz (!ip4_ok || params[1].jp_valuelen == 0) ? "-" 421194869Sjamie : inet_ntoa(*(struct in_addr *)params[1].jp_value), 422232613Sbz (char *)params[2-!ip4_ok].jp_value, 423232613Sbz (char *)params[3-!ip4_ok].jp_value); 424222465Sbz#else 425223224Sbz "-", 426232613Sbz (char *)params[1].jp_value, 427232613Sbz (char *)params[2].jp_value); 428222465Sbz#endif 429250736Sdes } else { 430194869Sjamie param_values = alloca(nparams * sizeof(*param_values)); 431194869Sjamie for (i = 0; i < nparams; i++) { 432194869Sjamie if (!(params[i].jp_flags & JP_USER)) 433194869Sjamie continue; 434194869Sjamie param_values[i] = jailparam_export(params + i); 435194869Sjamie if (param_values[i] == NULL) 436194869Sjamie errx(1, "%s", jail_errmsg); 437194869Sjamie } 438192896Sjamie for (i = spc = 0; i < nparams; i++) { 439194869Sjamie if (!(params[i].jp_flags & JP_USER)) 440149081Spjd continue; 441192896Sjamie if ((pflags & PRINT_SKIP) && 442194869Sjamie ((!(params[i].jp_ctltype & 443194869Sjamie (CTLFLAG_WR | CTLFLAG_TUN))) || 444195870Sjamie (param_parent[i] >= 0 && 445195870Sjamie *(int *)params[param_parent[i]].jp_value != 446195870Sjamie JAIL_SYS_NEW))) 447192896Sjamie continue; 448192896Sjamie if (spc) 449192896Sjamie putchar(' '); 450192896Sjamie else 451192896Sjamie spc = 1; 452192896Sjamie if (pflags & PRINT_NAMEVAL) { 453192896Sjamie /* 454192896Sjamie * Generally "name=value", but for booleans 455192896Sjamie * either "name" or "noname". 456192896Sjamie */ 457194869Sjamie if (params[i].jp_flags & 458194869Sjamie (JP_BOOL | JP_NOBOOL)) { 459194869Sjamie if (*(int *)params[i].jp_value) 460194869Sjamie printf("%s", params[i].jp_name); 461192896Sjamie else { 462194869Sjamie nname = (params[i].jp_flags & 463194869Sjamie JP_NOBOOL) ? 464194869Sjamie nononame(params[i].jp_name) 465194869Sjamie : noname(params[i].jp_name); 466192896Sjamie printf("%s", nname); 467192896Sjamie free(nname); 468192896Sjamie } 469194869Sjamie continue; 470192896Sjamie } 471194869Sjamie printf("%s=", params[i].jp_name); 472149081Spjd } 473194869Sjamie if (params[i].jp_valuelen == 0) { 474192896Sjamie if (pflags & PRINT_QUOTED) 475192896Sjamie printf("\"\""); 476192896Sjamie else if (!(pflags & PRINT_NAMEVAL)) 477192896Sjamie putchar('-'); 478194869Sjamie } else 479194869Sjamie quoted_print(param_values[i]); 480113277Smike } 481192896Sjamie putchar('\n'); 482194869Sjamie for (i = 0; i < nparams; i++) 483194869Sjamie if (params[i].jp_flags & JP_USER) 484194869Sjamie free(param_values[i]); 485149081Spjd } 486192896Sjamie return (jid); 487192896Sjamie} 488113277Smike 489192896Sjamiestatic void 490194869Sjamiequoted_print(char *str) 491192896Sjamie{ 492192896Sjamie int c, qc; 493192896Sjamie char *p = str; 494192896Sjamie 495192896Sjamie /* An empty string needs quoting. */ 496192896Sjamie if (!*p) { 497192896Sjamie fputs("\"\"", stdout); 498192896Sjamie return; 499113277Smike } 500192896Sjamie 501192896Sjamie /* 502192896Sjamie * The value will be surrounded by quotes if it contains spaces 503192896Sjamie * or quotes. 504192896Sjamie */ 505192896Sjamie qc = strchr(p, '\'') ? '"' 506192896Sjamie : strchr(p, '"') ? '\'' 507192896Sjamie : strchr(p, ' ') || strchr(p, '\t') ? '"' 508192896Sjamie : 0; 509192896Sjamie if (qc) 510192896Sjamie putchar(qc); 511194869Sjamie while ((c = *p++)) { 512192896Sjamie if (c == '\\' || c == qc) 513192896Sjamie putchar('\\'); 514192896Sjamie putchar(c); 515185435Sbz } 516192896Sjamie if (qc) 517192896Sjamie putchar(qc); 518113277Smike} 519