PageRenderTime 60ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/usr/src/suites/security/audit/src/lib/ksh/audit_zone.ksh

https://bitbucket.org/illumos/illumos-stc
Korn Shell | 676 lines | 491 code | 66 blank | 119 comment | 54 complexity | 64f8d55293bd17b12ba241683868ff05 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. #
  2. # CDDL HEADER START
  3. #
  4. # The contents of this file are subject to the terms of the
  5. # Common Development and Distribution License (the "License").
  6. # You may not use this file except in compliance with the License.
  7. #
  8. # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  9. # or http://www.opensolaris.org/os/licensing.
  10. # See the License for the specific language governing permissions
  11. # and limitations under the License.
  12. #
  13. # When distributing Covered Code, include this CDDL HEADER in each
  14. # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15. # If applicable, add the following below this CDDL HEADER, with the
  16. # fields enclosed by brackets "[]" replaced with your own identifying
  17. # information: Portions Copyright [yyyy] [name of copyright owner]
  18. #
  19. # CDDL HEADER END
  20. #
  21. #
  22. # Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  23. #
  24. . ${CTI_SUITE}/include/commands
  25. . ${CTI_SUITE}/include/vars
  26. . ${CTI_SUITE}/lib/audit_tx
  27. #
  28. # NAME
  29. # is_global
  30. #
  31. # ARGUMENTS
  32. #
  33. # DESCRIPTION
  34. # Function returns 0 on success - called from the global zone or 1 in
  35. # case of execution from the local zone.
  36. function is_global
  37. {
  38. typeset -r fn=is_global
  39. debug "${fn}: entered."
  40. if [[ "$(${ZONENAME})" != "global" ]]; then
  41. debug "${fn}: called from the local zone."
  42. debug "${fn}: exited (1)."
  43. return 1
  44. fi
  45. debug "${fn}: called from the global zone."
  46. debug "${fn}: exited (0)."
  47. return 0
  48. }
  49. #
  50. # NAME
  51. # zone_prepare
  52. #
  53. # ARGUMENTS
  54. # arg1 zonetype [default=sparse|wholeroot]
  55. # arg2 zonename - must be uniqueue across the system (tested)
  56. # arg3 zonepath [default=/zones]
  57. #
  58. #
  59. # DESCRIPTION
  60. # Function creates and prepares for boot local zone zonename (arg2) of
  61. # type zonetype (arg1) mounted in the zonepath/zonename (arg3). Function
  62. # returns 0 on success - zone successfully created and installed, or 1 in
  63. # case of any error found during function processing. Function keeps
  64. # system clean/unconfigured if returns with 1.
  65. #
  66. # In case the sparse zone ought to be created (arg1 = default|sparse),
  67. # then /lib, /platform, /sbin, /usr are to be shared between global and
  68. # the local zone. Note, that currently the sparse zone configuration for
  69. # the ipkg zone is not supported, thus such a combination triggers the
  70. # error and the function returns 1.
  71. #
  72. # Note, that this function does not support branded zone creation; which
  73. # means, that the brand = native|ipkg for all zone configuration created
  74. # by this function.
  75. #
  76. # Programmers note - the function is currently quite monolithic; and it's
  77. # like that by purpose since the initial programmer thinks that splitting
  78. # it may confuse consumers by using further split parts of the function.
  79. # It could be implemented in the future, but such consolidating functions
  80. # simplifying zone_prepare() would have to have again strong internal
  81. # checks of the arguments (sanity checks). For now it seems to be
  82. # reasonable to let the function flow as it is..
  83. function zone_prepare
  84. {
  85. typeset -r fn=zone_prepare
  86. debug "${fn}: entered."
  87. if (( $# != 3 )); then
  88. cti_report "${fn}: bad amount of args ($#)"
  89. debug "${fn}: exited (1)."
  90. return 1
  91. fi
  92. is_global
  93. if (( $? != 0 )); then
  94. cti_report "Cannot be executed from the local zone."
  95. debug "${fn}: Incorrectly executed from the local zone."
  96. debug "${fn}: exited (1)."
  97. return 1
  98. fi
  99. typeset i # temp variable for cycles
  100. typeset j # temp variable for cycles
  101. typeset rpasswd # root password for the zone
  102. typeset hexlabel # hexlabel for TX enabled systems
  103. typeset tmpfile # temporary file
  104. typeset zonetype="${1}"
  105. typeset -r zonename="${2}"
  106. typeset zonepath="${3}"
  107. typeset zonebrand="native"
  108. typeset -r timezone="$(${AWK} -F= '/^TZ/ { print $2 }' /etc/TIMEZONE)"
  109. typeset def_zonexml="/etc/zones/SUNWdefault.xml"
  110. typeset ipg_zonexml="/etc/zones/SUNWipkg.xml"
  111. if [[ "${zonepath}" == "default" ]]; then
  112. zonepath="/zones"
  113. fi
  114. if [[ "${zonetype}" == "default" ]]; then
  115. zonetype="sparse"
  116. fi
  117. debug "${fn}: zonetype=${zonetype}"
  118. debug "${fn}: zonename=${zonename}"
  119. debug "${fn}: zonepath=${zonepath}"
  120. #
  121. # Some sanity checks:
  122. case "${zonetype}" in
  123. "sparse")
  124. #
  125. # ipkg zone brand testing
  126. if [[ ! -f "${def_zonexml}" ]]; then
  127. cti_report "Cannot access ${def_zonexml}."
  128. debug "${fn}: no such file ${def_zonexml}"
  129. debug "${fn}: exited (1)."
  130. return 1
  131. fi
  132. if [[ -n "$(${FGREP} brand=\"ipkg\" ${def_zonexml})" ]]; then
  133. cti_report "Sparse zone not supported on ipkg systems"
  134. debug "${fn}: (default) system detected as brand=ipkg."
  135. debug "${fn}: Falling back to the wholeroot zone."
  136. zonetype="wholeroot"
  137. fi
  138. if [[ -f "${ipg_zonexml}" ]]; then
  139. cti_report "Sparse zone not supported on ipkg systems"
  140. debug "${fn}: Falling back to the wholeroot zone."
  141. zonetype="wholeroot"
  142. fi
  143. ;;
  144. "wholeroot")
  145. ;;
  146. *)
  147. cti_report "Unknown zone type build requested (${zonetype})"
  148. debug "${fn}: exited (1)."
  149. return 1
  150. ;;
  151. esac
  152. #
  153. # XXX - The following code is just a workaround for badly behaving zones
  154. # and zone configuration in OpenSolaris. Bear in mind, that the XXX
  155. # steps are just a raw patch and can be removed once the particular bugs
  156. # are resolved.
  157. # XXX - 1) set the zonebrand to ipkg - Bug 10950
  158. if [[ -x "/usr/sbin/beadm" ]]; then
  159. zonebrand="ipkg"
  160. debug "${fn}: zonebrand changed: zonebrand=${zonebrand}"
  161. fi
  162. #
  163. # XXX - 2) create a zfs filesystem for the zone - Bug 10455
  164. if [[ "${zonebrand}" == "ipkg" ]]; then
  165. ${ZFS} create -o mountpoint=/zones rpool/zones
  166. fi
  167. #
  168. # check whether the system is TX enabled
  169. if [[ "$(${SVCS} -o state svc:/system/labeld:default 2>/dev/null | \
  170. ${AWK} '$1 !~ /STATE/ { print $1 }')" == "online" ]]; then
  171. zonebrand="labeled"
  172. debug "${fn}: zonebrand changed: zonebrand=${zonebrand}"
  173. hexlabel="$(${ATOHEXLABEL} "${TX_ZONE_LABEL}")"
  174. if ! add_tnzonecfg_data "${zonename}" "${hexlabel}"; then
  175. cti_report "Unable to update ${TNZONECFG}."
  176. debug "${fn}: exited (1)."
  177. return 1
  178. fi
  179. if ! add_tnrhtp_data "${zonename}" "${hexlabel}"; then
  180. cti_report "Unable to update ${TNRHTP}."
  181. debug "${fn}: exited (1)."
  182. return 1
  183. fi
  184. if ! ${TNCHKDB} 1>/dev/null 2>/dev/null; then
  185. cti_report "Errors detected in TX configuration."
  186. cti_report "See: tnchkdb(1M) for more information."
  187. debug "${fn}: exited (1)."
  188. return 1
  189. fi
  190. ${SVCADM} restart svc:/network/tnctl
  191. debug "${fn}: svc:/network/tnctl restarted"
  192. fi
  193. if [[ -n "$(${ZONEADM} list -i | ${FGREP} ^${zonename}$)" ]]; then
  194. cti_report "Zonename ${zonename} already exists in the system"
  195. debug "${fn}: exited (1)."
  196. return 1
  197. fi
  198. zonepath="${zonepath}/${zonename}"
  199. if [[ -d "${zonepath}" ]]; then
  200. cti_report "Zonepath ${zonepath} already exists in the system"
  201. debug "${fn}: exited (1)."
  202. return 1
  203. fi
  204. #
  205. # Configure the zone - ${zonename}
  206. ${ZONECFG} -z "${zonename}" -f - << __EOConfig__
  207. create -b
  208. set zonepath=${zonepath}
  209. set brand=${zonebrand}
  210. $(if [[ "${zonetype}" == "sparse" ]]; then \
  211. for i in /lib /platform /sbin /usr; do \
  212. print "add inherit-pkg-dir"; \
  213. print "set dir=${i}"; \
  214. print "end"; \
  215. done; fi)
  216. commit
  217. exit
  218. __EOConfig__
  219. if (( $? != 0 )); then
  220. cti_report "zone ${zonename} configuration failed"
  221. debug "${fn}: exited (1)."
  222. return 1
  223. fi
  224. debug "${fn}: zone ${zonename} successfully configured."
  225. #
  226. # Install the zone
  227. ${ZONEADM} -z "${zonename}" install
  228. if (( $? != 0 )); then
  229. cti_report "zone ${zonename} installation failed"
  230. ${ZONEADM} -z "${zonename}" delete
  231. debug "${fn}: zone ${zonename} configuration deleted."
  232. debug "${fn}: exited (1)."
  233. return 1
  234. fi
  235. debug "${fn}: zone ${zonename} successfully installed."
  236. #
  237. # Ready the zone
  238. ${ZONEADM} -z "${zonename}" ready
  239. #
  240. # Do a pre-boot zone configuration - generate sysidcfg(4)
  241. typeset nameservice="NONE"
  242. typeset nameservice_tmp="$(${GREP} ^hosts: /etc/nsswitch.conf | ${AWK} \
  243. '{
  244. i = 2;
  245. while ( i < NF ) {
  246. if ( substr($i, 1) == "[" ) {
  247. i++;
  248. continue;
  249. };
  250. print $i;
  251. i++;
  252. };
  253. }')"
  254. # the first available NIS|DNS is set up as a name service for the zone
  255. for nameservice_tmp in ${nameservice_tmp}; do
  256. case "${nameservice_tmp}" in
  257. "dns")
  258. debug "${fn}: DNS name service recognized and used."
  259. if [[ ! -f /etc/resolv.conf ]]; then
  260. continue
  261. fi
  262. nameservice="DNS"
  263. i="$(${GREP} ^domain /etc/resolv.conf | ${TAIL} -1 | \
  264. ${AWK} '{ print $2 }' | \
  265. ${TR} "[:upper:]" "[:lower:]")"
  266. if [[ -z "${i}" ]]; then
  267. debug "${fn}: no domain definition found in "\
  268. "the /etc/resolv.conf."
  269. i="$(${HOSTNAME})"
  270. j="$(${HOST} ${i})"
  271. j="${j%% *}"
  272. eval i="\${j#$i.}"
  273. debug "${fn}: will use domain_name=${i}"
  274. fi
  275. nameservice="${nameservice} {domain_name=${i}"
  276. j=
  277. for i in $(${GREP} ^nameserver /etc/resolv.conf | \
  278. ${HEAD} -3 | ${AWK} '{ print $2 }'); do
  279. j="${j:+${j},}"
  280. j="${j}${i}"
  281. done
  282. nameservice="${nameservice} name_server=${j}"
  283. i="$(${GREP} ^search /etc/resolv.conf | ${TAIL} -1 | \
  284. ${AWK} '{
  285. i = 2;
  286. while ( i < NF && i < 8) {
  287. if (i > 2) {
  288. printf "%s", ",";
  289. }
  290. printf "%s", $i;
  291. i++;
  292. }
  293. }')"
  294. if [[ -n "${i}" ]]; then
  295. nameservice="${nameservice} search=${i}}"
  296. else
  297. nameservice="${nameservice}}"
  298. fi
  299. break
  300. ;;
  301. "nis")
  302. debug "${fn}: NIS name service recognized and used."
  303. nameservice="NIS"
  304. i="$(${DOMAINNAME} | ${TR} "[:upper:]" "[:lower:]")"
  305. nameservice="${nameservice} {domain_name=${i}"
  306. i="$(${YPWHICH} | ${TR} "[:upper:]" "[:lower:]")"
  307. if [[ -z "${i}" ]]; then
  308. cti_report "No NIS server configured."
  309. nameservice=
  310. continue;
  311. fi
  312. j="$(${GETENT} hosts ${i} | ${AWK} '{ print $1"="$2 }')"
  313. if [[ -z "${j}" ]]; then
  314. cti_report "Cannot resolve host name for ${i}."
  315. nameservice=
  316. continue;
  317. fi
  318. if [[ "${j%%=*}" == "${i}" ]]; then
  319. cti_report "NIS server configured as an" \
  320. "IP address not a hostname."
  321. i="${j##*=}"
  322. fi
  323. j="${j%%=*}"
  324. nameservice="${nameservice} name_server=${i}(${j})}"
  325. break
  326. ;;
  327. *)
  328. cti_report "Service ${nameservice_tmp} not supported."
  329. continue
  330. ;;
  331. esac
  332. done
  333. debug "${fn}: finished constructing name_service=${nameservice}"
  334. # XXX - 3) use crypted password (traditional unix) - Bug 6863728
  335. # rpasswd="$(${AWK} -F: '/^root:/ { print $2 }' /etc/shadow)"
  336. rpasswd="MW8T79hI9lQA6" # tet123
  337. if [[ "${zonebrand}" == "labeled" ]]; then
  338. ${CAT} > "${zonepath}/root/etc/sysidcfg" << __EOsysidcfg__
  339. system_locale=C
  340. terminal=xterm
  341. security_policy=NONE
  342. name_service=${nameservice}
  343. timezone=${timezone}
  344. root_password=${rpasswd}
  345. nfs4_domain=dynamic
  346. network_interface=PRIMARY {hostname=${zonename}}
  347. __EOsysidcfg__
  348. else
  349. ${CAT} > "${zonepath}/root/etc/sysidcfg" << __EOsysidcfg__
  350. system_locale=C
  351. terminal=xterm
  352. network_interface=NONE {hostname=${zonename}}
  353. security_policy=NONE
  354. name_service=${nameservice}
  355. timezone=${timezone}
  356. root_password=${rpasswd}
  357. nfs4_domain=dynamic
  358. __EOsysidcfg__
  359. fi
  360. debug "${fn}: ${zonepath}/root/etc/sysidcfg created."
  361. # XXX - 4) ksh bug - 6946957, 6950013
  362. #debug "${fn}: $(${CAT} ${zonepath}/root/etc/sysidcfg)"
  363. #
  364. # Update zone nodename (TX enabled system fails to initiate nodename
  365. # based on the sysidcfg contents (hostname=).
  366. if [[ "${zonebrand}" == "labeled" ]]; then
  367. print "${zonename}" > ${zonepath}/root/etc/nodename
  368. debug "${fn}: ${zonepath}/root/etc/nodename nodename" \
  369. "set to ${zonename}"
  370. fi
  371. #
  372. # Update the GZ loopback IPv4 address to be resolved from ${zonename}.
  373. if [[ "${zonebrand}" == "labeled" ]]; then
  374. tmpfile="$($MKTEMP /tmp/hosts.XXXXXXXX)"
  375. ${SED} -e "s/^\(127.0.0.1\)\(.*\)$/\1 ${zonename} \2/" \
  376. /etc/inet/hosts > ${tmpfile} 2>/dev/null
  377. mv ${tmpfile} /etc/inet/hosts 2>/dev/null
  378. debug "${fn}: /etc/inet/hosts regenerated."
  379. fi
  380. debug "${fn}: exited (0)."
  381. return 0
  382. }
  383. #
  384. # NAME
  385. # zone_destroy
  386. #
  387. # ARGUMENTS
  388. # arg1 zonename
  389. #
  390. # DESCRIPTION
  391. # Function uninstalls the zone and deletes the zone configuration.
  392. # Function returns 0 on success - zone successfully removed,
  393. # or 1 in case of any error found during function processing.
  394. function zone_destroy
  395. {
  396. typeset -r fn=zone_destroy
  397. debug "${fn}: entered."
  398. if (( $# != 1 )); then
  399. cti_report "${fn}: bad amount of args ($#)"
  400. debug "${fn}: exited (1)."
  401. return 1
  402. fi
  403. is_global
  404. if (( $? != 0 )); then
  405. cti_report "Cannot be executed from the local zone."
  406. debug "${fn}: Incorrectly executed from the local zone."
  407. debug "${fn}: exited (1)."
  408. return 1
  409. fi
  410. typeset -r zonename="${1}"
  411. typeset zonestate=
  412. debug "${fn}: zonename=${zonename}"
  413. #
  414. # halt && uninstall && unconfigure
  415. zonestate="$(${ZONEADM} list -pc | \
  416. ${NAWK} -F\: '$2 ~ /'"${zonename}"'/ { print $3 }')"
  417. debug "${fn}: ${zonename} - zonestate=${zonestate}"
  418. #
  419. # XXX - The following code is just a workaround for badly behaving zones
  420. # and zone configuration in OpenSolaris. Bear in mind, that the XXX
  421. # steps are just a raw patch and can be removed once the particular bugs
  422. # are resolved.
  423. # XXX - 0) set the brand of the zone
  424. typeset -r zonebrand="$(${ZONEADM} list -pc | \
  425. ${NAWK} -F\: '$2 ~ /'"${zonename}"'/ { print $6 }')"
  426. if [[ -n "${zonestate}" ]]; then
  427. case "${zonestate}" in
  428. "running")
  429. ${ZONEADM} -z ${zonename} halt
  430. ${ZONEADM} -z ${zonename} uninstall -F
  431. ${ZONECFG} -z ${zonename} delete -F
  432. ;;
  433. "installed"|"incomplete")
  434. ${ZONEADM} -z ${zonename} uninstall -F
  435. ${ZONECFG} -z ${zonename} delete -F
  436. ;;
  437. "configured")
  438. ${ZONECFG} -z ${zonename} delete -F
  439. ;;
  440. *)
  441. cti_report "Unknown zone state: ${zonestate}"
  442. ;;
  443. esac
  444. if [[ -n "$(${ZONEADM} list -pc | ${FGREP} ":${zonename}:")" ]]
  445. then
  446. cti_report "Zone: ${zonename} wasn't fully removed."
  447. debug "${fn}: $(${ZONEADM} list -pc | \
  448. ${FGREP} ":${zonename}:")"
  449. debug "${fn}: exited (1)."
  450. return 1
  451. fi
  452. # XXX - 1) destroy a zfs filesystem for the zone - Bug 10455
  453. if [[ "${zonebrand}" == "ipkg" || \
  454. "${zonebrand}" == "labeled" ]]; then
  455. ${ZFS} destroy -rf rpool/zones
  456. fi
  457. if [[ "${zonebrand}" == "labeled" ]]; then
  458. del_tnzonecfg_data "${zonename}"
  459. del_tnrhtp_data "${zonename}"
  460. if ! ${TNCHKDB} 1>/dev/null 2>/dev/null; then
  461. cti_report "Errors detected in TX config."
  462. cti_report "See: tnchkdb(1M) for more info."
  463. debug "${fn}: exited (1)."
  464. return 1
  465. fi
  466. ${SVCADM} restart svc:/network/tnctl
  467. debug "${fn}: svc:/network/tnctl restarted"
  468. fi
  469. else
  470. cti_report "No such zone ${zonename} installed/running."
  471. cti_report "Halt/Uninstall phase for the ${zonename} skipped."
  472. fi
  473. #
  474. # Remove the ${tzone} from the /etc/inet/hosts.
  475. if [[ "${zonebrand}" == "labeled" ]]; then
  476. tmpfile="$($MKTEMP /tmp/hosts.XXXXXXXX)"
  477. ${SED} -e "s/^\(127.0.0.1\) ${zonename} \(.*\)$/\1\2/" \
  478. /etc/inet/hosts > ${tmpfile} 2>/dev/null
  479. mv ${tmpfile} /etc/inet/hosts 2>/dev/null
  480. debug "${fn}: /etc/inet/hosts regenerated."
  481. fi
  482. debug "${fn}: exited (0)."
  483. return 0
  484. }
  485. #
  486. # NAME
  487. # zone_booted
  488. #
  489. # ARGUMENTS
  490. # arg1 zonename
  491. # arg2 timeout
  492. #
  493. # DESCRIPTION
  494. # Function waits until the zone zonename/arg1 has been in booted state.
  495. # Fully booted state is checked via online state of the
  496. # svc:/milestone/sysconfig:default milestone service. Checking against
  497. # this service overcomes the issue with reboot of the zone after its
  498. # reconfiguration based on the sysidcfg(4) values. Function returns 0 on
  499. # success - zone is reconfigured / booted. If the timeout/arg2 is reached
  500. # without successfully detected zone in booted state, function returns 1.
  501. # If the timeout equals zero, function blocks/cycles in 5 second steps
  502. # untill the zone is fully booted.
  503. function zone_booted
  504. {
  505. typeset -r fn=zone_booted
  506. debug "${fn}: entered."
  507. if (( $# != 2 )); then
  508. cti_report "${fn}: bad amount of args ($#)"
  509. debug "${fn}: exited (1)."
  510. return 1
  511. fi
  512. is_global
  513. if (( $? != 0 )); then
  514. cti_report "Cannot be executed from the local zone."
  515. debug "${fn}: Incorrectly executed from the local zone."
  516. debug "${fn}: exited (1)."
  517. return 1
  518. fi
  519. typeset -r zonename="${1}"
  520. typeset -i timeout="${2}"
  521. typeset -i blocking_loop=0
  522. typeset sysconfig_state=
  523. debug "${fn}: zonename=${zonename}"
  524. debug "${fn}: timeout=${timeout}"
  525. if (( timeout == 0 )); then
  526. blocking_loop=1
  527. fi
  528. while ${TRUE}; do
  529. sysconfig_state="$(${ZLOGIN} ${zonename} ${SVCS} -Ho state \
  530. svc:/milestone/sysconfig:default)"
  531. if [[ "${sysconfig_state}" == "online" ]]; then
  532. cti_report "Zone ${zonename} is online".
  533. break
  534. fi
  535. ${SLEEP} 5
  536. if (( !blocking_loop )); then
  537. timeout=$(( timeout - 5 ))
  538. if (( timeout < 0 )); then
  539. cti_report "Fully booted zone test timed out."
  540. debug "${fn}: exited (1)."
  541. return 1
  542. fi
  543. fi
  544. done
  545. debug "${fn}: exited (0)."
  546. return 0
  547. }
  548. #
  549. # NAME
  550. # get_zone_status
  551. #
  552. # ARGUMENTS
  553. # arg1 zonename
  554. #
  555. # DESCRIPTION
  556. # Prints the current state of the zone and returns 0; nothis is prited out
  557. # along with returning 1 in case the zone doesn't exist (zone is not
  558. # configured / installed / ..). See zoneadm(1M) list for all the known
  559. # states returned by the function.
  560. function get_zone_status
  561. {
  562. typeset -r fn=get_zone_status
  563. debug "${fn}: entered."
  564. if (( $# != 1 )); then
  565. cti_report "${fn}: bad amount of args ($#)"
  566. debug "${fn}: exited (1)."
  567. return 1
  568. fi
  569. is_global
  570. if (( $? != 0 )); then
  571. cti_report "Cannot be executed from the local zone."
  572. debug "${fn}: Incorrectly executed from the local zone."
  573. debug "${fn}: exited (1)."
  574. return 1
  575. fi
  576. typeset -r zonename="${1}"
  577. typeset zonestate=
  578. typeset sysconfig_state=
  579. debug "${fn}: zonename=${zonename}"
  580. zonestate="$(${ZONEADM} list -pc | \
  581. ${NAWK} -F\: '$2 ~ /'"${zonename}"'/ { print $3 }')"
  582. if [[ -z "${zonestate}" ]]; then
  583. debug "${fn}: Zone ${zonename} not configured."
  584. debug "${fn}: exited (1)."
  585. return 1
  586. fi
  587. print -n "${zonestate}"
  588. debug "${fn}: exited (0)."
  589. return 1
  590. }