]> git.ipfire.org Git - people/stevee/network.git/blob - src/functions/functions.zone
config hook: prevent two hooks with the same settings
[people/stevee/network.git] / src / functions / functions.zone
1 #!/bin/bash
2 ###############################################################################
3 # #
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2010 Michael Tremer & Christian Schmidt #
6 # #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
11 # #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
16 # #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 # #
20 ###############################################################################
21
22 zone_dir() {
23 local zone=${1}
24
25 echo "${NETWORK_ZONE_DIR}/zones/${zone}"
26 }
27
28 zone_exists() {
29 local zone=${1}
30 assert isset zone
31
32 [ -d "$(zone_dir ${zone})" ]
33 }
34
35 zone_match() {
36 local match
37
38 local i
39 for i in ${VALID_ZONES}; do
40 match="${match}|${i}[0-9]{1,5}"
41 done
42
43 echo "${match:1:${#match}}"
44 }
45
46 zone_name_is_valid() {
47 local zone=${1}
48
49 # Don't accept empty strings.
50 [ -z "${zone}" ] && return ${EXIT_FALSE}
51
52 [[ ${zone} =~ $(zone_match) ]]
53 }
54
55 zone_is_local() {
56 local zone=${1}
57
58 [[ "${zone:0:${#ZONE_LOCAL}}" = "${ZONE_LOCAL}" ]]
59 }
60
61 zone_is_nonlocal() {
62 local zone=${1}
63
64 [[ "${zone:0:${#ZONE_NONLOCAL}}" = "${ZONE_NONLOCAL}" ]]
65 }
66
67 zone_get_hook() {
68 local zone=${1}
69 assert isset zone
70
71 config_get_hook $(zone_dir ${zone})/settings
72 }
73
74 zone_start() {
75 # This function will bring up the zone
76 # 'asynchronously' with help of systemd.
77
78 local zone=${1}
79 assert zone_exists ${zone}
80
81 service_start "network@${zone}.service"
82 }
83
84 zone_start_auto() {
85 local zone="${1}"
86 assert zone_exists "${zone}"
87
88 # If the zone has already been started, we
89 # will reload it so the current configuration
90 # is re-applied.
91 if zone_is_active "${zone}"; then
92 zone_reload "${zone}"
93 return ${?}
94
95 # If the zone is still down, but in auto-start mode,
96 # we will start it.
97 elif zone_is_enabled "${zone}"; then
98 zone_start "${zone}"
99 return ${?}
100 fi
101
102 # Otherwise, nothing will be done.
103 return ${EXIT_OK}
104 }
105
106 zone_stop() {
107 # This function will bring down the zone
108 # 'asynchronously' with help of systemd.
109
110 local zone=${1}
111 assert zone_exists ${zone}
112
113 service_stop "network@${zone}.service"
114 }
115
116 zone_reload() {
117 local zone="${1}"
118 assert zone_exists "${zone}"
119
120 service_reload "network@${zone}.service"
121 }
122
123 zone_hotplug_event() {
124 local zone="${1}"
125 assert isset zone
126
127 hotplug_assert_in_hotplug_event
128
129 zone_cmd "hotplug" "${zone}"
130 }
131
132 zone_enable() {
133 # This function will enable the zone
134 # with help of systemd.
135
136 local zone="${1}"
137 assert zone_exists "${zone}"
138
139 # Enable service for the zone
140 service_enable "network@${zone}.service"
141 local ret=$?
142
143 if [ ${ret} -eq ${EXIT_OK} ]; then
144 log INFO "Auto-start enabled for zone ${zone}"
145 return ${EXIT_OK}
146 fi
147
148 log ERROR "Could not enable zone ${zone}: ${ret}"
149 return ${ret}
150 }
151
152 zone_disable() {
153 # This function will disable the zone
154 # with help of systemd.
155
156 local zone="${1}"
157 assert zone_exists "${zone}"
158
159 # Disable service for the zone
160 service_disable "network@${zone}.service"
161 local ret=$?
162
163 if [ ${ret} -eq ${EXIT_OK} ]; then
164 log INFO "Auto-start disabled for zone ${zone}"
165 return ${EXIT_OK}
166 fi
167
168 log ERROR "Could not disable zone ${zone}: ${ret}"
169 return ${ret}
170 }
171
172 zone_is_enabled() {
173 local zone="${1}"
174 assert isset zone
175
176 # Ask systemd if the zone is enabled.
177 if service_is_enabled "network@${zone}.service"; then
178 return ${EXIT_TRUE}
179 fi
180
181 return ${EXIT_FALSE}
182 }
183
184 zone_is_active() {
185 local zone="${1}"
186 assert isset zone
187
188 if service_is_active "network@${zone}.service"; then
189 return ${EXIT_TRUE}
190 fi
191
192 return ${EXIT_FALSE}
193 }
194
195 zone_is_enabled_or_active() {
196 local zone="${1}"
197 assert isset zone
198
199 zone_is_enabled "${zone}" || zone_is_active "${zone}"
200 }
201
202 zone_cmd() {
203 local cmd="${1}"
204 local port="${2}"
205 shift 2
206
207 assert isset cmd
208 assert isset zone
209
210 local hook="$(zone_get_hook ${zone})"
211 assert isset hook
212
213 hook_exec zone "${hook}" "${cmd}" "${zone}" $@
214 }
215
216 zone_new() {
217 local zone=${1}
218 local hook=${2}
219 shift 2
220
221 if ! zone_name_is_valid ${zone}; then
222 error "Zone name '${zone}' is not valid."
223 return ${EXIT_ERROR}
224 fi
225
226 if zone_exists ${zone}; then
227 error "Zone '${zone}' does already exist."
228 return ${EXIT_ERROR}
229 fi
230
231 if ! hook_zone_exists ${hook}; then
232 error "Hook '${hook}' does not exist."
233 return ${EXIT_ERROR}
234 fi
235
236 mkdir -p $(zone_dir ${zone})
237
238 # Create directories for configs and ports
239 mkdir -p $(zone_dir ${zone})/{configs,ports}
240
241 hook_zone_exec "${hook}" "new" "${zone}" $@
242 local ret=$?
243
244 # Maybe the zone new hook did not exit correctly.
245 # If this is the case we remove the created zone immediately.
246 if [ "${ret}" != "${EXIT_OK}" ]; then
247 zone_destroy_now "${zone}"
248 return ${EXIT_ERROR}
249 fi
250
251 # Automatically enable zone.
252 zone_enable "${zone}"
253
254 # Bring up the zone immediately after
255 zone_start "${zone}"
256 }
257
258 zone_edit() {
259 local zone=${1}
260 shift
261
262 if ! zone_exists ${zone}; then
263 error "Zone '${zone}' does not exist."
264 return ${EXIT_ERROR}
265 fi
266
267 # Check if the zone is tagged for removal.
268 if zone_has_destroy_tag ${zone}; then
269 error "You cannot edit a zone that is tagged for removal."
270 return ${EXIT_ERROR}
271 fi
272
273 local hook="$(zone_get_hook "${zone}")"
274 if [ -z "${hook}" ]; then
275 error "Config file did not provide any hook."
276 return ${EXIT_ERROR}
277 fi
278
279 if ! hook_zone_exists ${hook}; then
280 error "Hook '${hook}' does not exist."
281 return ${EXIT_ERROR}
282 fi
283
284 hook_zone_exec ${hook} edit ${zone} $@
285 }
286
287 zone_rename() {
288 assert [ $# -eq 2 ]
289
290 local zone="${1}"
291 local name="${2}"
292
293 assert zone_exists "${zone}"
294 assert not zone_has_destroy_tag "${zone}"
295 assert not zone_exists "${name}"
296
297 # The zone must be shut down before, is then renamed and
298 # potentially brought up again
299
300 # Save if the zone is running right now
301 zone_is_active "${zone}"
302 local zone_was_active="${?}"
303
304 # Save if the zone is enabled (i.e. auto-start)
305 zone_is_enabled "${zone}"
306 local zone_was_enabled="${?}"
307
308 # Stop the zone
309 zone_stop "${zone}"
310
311 # Disable the zone
312 zone_disable "${zone}"
313
314 # Rename the configuration files
315 mv -f "$(zone_dir "${zone}")" "$(zone_dir "${name}")"
316
317 # Enable the zone if it was enabled before
318 [ ${zone_was_enabled} -eq ${EXIT_TRUE} ] && zone_enable "${name}"
319
320 # Start the zone if it was up before
321 [ ${zone_was_active} -eq ${EXIT_TRUE} ] && zone_start "${name}"
322
323 log INFO "Zone ${zone} was renamed to ${name}"
324 return ${EXIT_OK}
325 }
326
327
328 zone_destroy() {
329 local zone="${1}"
330 assert zone_exists "${zone}"
331
332 # Make the zone for removal.
333 touch "$(zone_dir "${zone}")/.destroy"
334
335 log INFO "Zone '${zone}' has been tagged for removal."
336 }
337
338 zone_has_destroy_tag() {
339 local zone="${1}"
340 assert zone_exists "${zone}"
341
342 [ -e "$(zone_dir "${zone}")/.destroy" ]
343 }
344
345 # This function will remove the given zone
346 # RIGHT NOW. Use zone_destroy to remove it
347 # at the next status change.
348 zone_destroy_now() {
349 local zone="${1}"
350 assert zone_exists "${zone}"
351
352 log INFO "Removing zone '${zone}' right now."
353
354 # Force the zone down.
355 zone_is_active "${zone}" && zone_stop "${zone}"
356
357 # Disable zone.
358 zone_disable "${zone}"
359
360 rm -rf "$(zone_dir "${zone}")"
361 }
362
363 zone_up() {
364 local zone=${1}
365 shift
366
367 if ! zone_exists ${zone}; then
368 error "Zone '${zone}' does not exist."
369 return ${EXIT_ERROR}
370 fi
371
372 # Check if a zone has got the remove tag.
373 if zone_has_destroy_tag ${zone}; then
374 error "Cannot bring up any zone which is to be removed."
375 return ${EXIT_ERROR}
376 fi
377
378 local hook="$(zone_get_hook "${zone}")"
379 if [ -z "${hook}" ]; then
380 error "Config file did not provide any hook."
381 return ${EXIT_ERROR}
382 fi
383
384 if ! hook_zone_exists ${hook}; then
385 error "Hook '${hook}' does not exist."
386 return ${EXIT_ERROR}
387 fi
388
389 zone_db ${zone} starting
390
391 hook_zone_exec ${hook} up ${zone} $@
392
393 zone_db ${zone} started
394
395 # Execute all triggers after the zone got up
396 triggers_execute_all "up" ZONE="${zone}"
397 }
398
399 zone_down() {
400 local zone=${1}
401 shift
402
403 if ! zone_exists ${zone}; then
404 error "Zone '${zone}' does not exist."
405 return ${EXIT_ERROR}
406 fi
407
408 local hook="$(zone_get_hook "${zone}")"
409 if [ -z "${hook}" ]; then
410 error "Config file did not provide any hook."
411 return ${EXIT_ERROR}
412 fi
413
414 if ! hook_zone_exists ${hook}; then
415 error "Hook '${hook}' does not exist."
416 return ${EXIT_ERROR}
417 fi
418
419 zone_db ${zone} stopping
420
421 hook_zone_exec ${hook} down ${zone} $@
422
423 zone_db ${zone} stopped
424
425 # Execute all triggers after the zone went down
426 triggers_execute_all "down" ZONE="${zone}"
427
428 # Remove the zone, if it has got a remove tag.
429 if zone_has_destroy_tag "${zone}"; then
430 zone_destroy_now "${zone}"
431 fi
432 }
433
434 zone_status() {
435 local zone="${1}"
436 assert isset zone
437 shift
438
439 if ! zone_exists "${zone}"; then
440 error "Zone '${zone}' does not exist."
441 return ${EXIT_ERROR}
442 fi
443
444 local hook="$(zone_get_hook "${zone}")"
445 if [ -z "${hook}" ]; then
446 error "Config file did not provide any hook."
447 return ${EXIT_ERROR}
448 fi
449
450 if ! hook_zone_exists "${hook}"; then
451 error "Hook '${hook}' does not exist."
452 return ${EXIT_ERROR}
453 fi
454
455 hook_zone_exec "${hook}" "status" "${zone}" "$@"
456
457 # Show that the zone it to be removed soon.
458 if zone_has_destroy_tag ${zone}; then
459 warning "This zone is tagged for removal."
460 fi
461 }
462
463 zone_identify() {
464 assert [ $# -ge 1 ]
465
466 local zone="${1}"
467 shift
468
469 assert zone_exists "${zone}"
470
471 log INFO "Identifying zone ${zone}"
472 local pids
473
474 local pid
475 local port
476 for port in $(zone_get_ports "${zone}"); do
477 # Identify all the ports
478 port_identify "${port}" --background $@
479
480 # Save the PIDs of the subprocesses
481 list_append pids "$(cmd_background_get_pid)"
482 done
483
484 # Wait until all port_identfy processes have finished
485 for pid in ${pids}; do
486 cmd_background_result "${pid}"
487 done
488
489 return ${EXIT_OK}
490 }
491
492 zone_get_ports() {
493 local zone=${1}
494
495 assert isset zone
496
497 local port
498 for port in $(zone_dir ${zone})/ports/*; do
499 port=$(basename ${port})
500
501 if port_exists ${port}; then
502 echo "${port}"
503 fi
504 done
505 }
506
507 zone_get_ports_num() {
508 local zone="${1}"
509 assert isset zone
510
511 local counter=0
512 local port
513 for port in $(zone_dir "${zone}")/ports/*; do
514 port="$(basename "${port}")"
515
516 if port_exists "${port}"; then
517 counter=$(( ${counter} + 1 ))
518 fi
519 done
520
521 echo "${counter}"
522 return ${EXIT_OK}
523 }
524
525 zone_has_port() {
526 # Check, if the given port is configured
527 # in this zone.
528
529 local zone=${1}
530 local port=${2}
531 shift 2
532
533 assert isset zone
534 assert isset port
535
536 [ -e "$(zone_dir ${zone})/ports/${port}" ]
537 }
538
539 zone_config() {
540 local zone="${1}"
541 local cmd="${2}"
542 shift 2
543
544 assert isset zone
545 assert isset cmd
546 assert zone_exists "${zone}"
547
548 case "${cmd}" in
549 new)
550 zone_config_new "${zone}" "$@"
551 ;;
552 destroy)
553 # usually ${1} is a valid hid
554 local hid=${1}
555 shift 1
556
557 # We convert the hid into an id
558 local id=$(zone_config_convert_hid_to_id ${zone} ${hid})
559
560 # If id isset the hid is valid and we can go on with the id
561 if isset id; then
562 zone_config_destroy "${zone}" "${id}" "$@"
563
564 # If we can't get a valid hid we check if we got a valid id
565 else
566 if zone_config_id_is_valid ${zone} ${hid}; then
567 zone_config_destroy "${zone}" ${hid} "$@"
568 else
569 log ERROR "${id} is not a valid id or hid"
570 fi
571 fi
572 ;;
573 list)
574 zone_config_list "${zone}" "$@"
575 ;;
576 *)
577 # usually ${1} is a valid hid
578 local hid=${cmd}
579 local cmd=${1}
580 shift 1
581
582 local id=$(zone_config_convert_hid_to_id ${zone} ${hid})
583
584 # If id isset the hid is valid and we can go on with the id
585 if isset id && [[ ${cmd} == "edit" ]]; then
586 zone_config_edit "${zone}" "${id}" "$@"
587
588 # If we didn't get a valid hid we check if we got a valid id
589 else
590 if zone_config_id_is_valid ${zone} ${id} && [[ ${cmd} == "edit" ]]; then
591 shift 1
592 zone_config_edit "${zone}" "${id}" "$@"
593 else
594 # in ${hid} is saved the command after network zone ${zone} config
595 error "Unrecognized argument: ${hid}"
596 cli_usage root-zone-config-subcommands
597 exit ${EXIT_ERROR}
598 fi
599 fi
600 ;;
601 esac
602 }
603
604 zone_config_cmd() {
605 assert [ $# -gt 2 ]
606
607 local cmd="${1}"
608 local zone="${2}"
609 shift 2
610
611 local hook="$(zone_get_hook "${zone}")"
612 assert isset hook
613
614 hook_zone_exec "${hook}" "config_${cmd}" "${zone}" "$@"
615 }
616
617 zone_config_new() {
618 local zone="${1}"
619 shift
620
621 # Create a new configuration, but exit when that was
622 # not successful.
623 zone_config_cmd "new" "${zone}" "$@" || return ${?}
624
625 # If the config could be created, we will try to bring
626 # it up if the zone is up, too.
627 if zone_is_up "${zone}"; then
628 zone_configs_up "${zone}"
629 fi
630 }
631
632 zone_config_destroy() {
633 zone_config_cmd "destroy" "$@"
634 }
635
636 zone_config_edit() {
637 zone_config_cmd "edit" "$@"
638 }
639
640 zone_config_list() {
641 # This function list in an nice way all configs of a zone
642 local zone=${1}
643 assert isset zone
644
645 # Print a nice header
646 local format="%-3s %-20s %-20s"
647 print "${format}" "ID" "HOOK" "HID"
648
649 local config
650 local hook
651 local id
652 local hid
653
654 # Print for all config:
655 # id and hook
656 for config in $(zone_configs_list "${zone}"); do
657 id=${config##*.}
658 hook=$(zone_config_get_hook "${zone}" "${config}")
659 hid=$(zone_config_get_hid "${zone}" "${config}")
660 assert isset hook
661 print "${format}" "${id}" "${hook}" "${hid}"
662 done
663 }
664
665 zone_config_show() {
666 zone_config_cmd "show" "$@"
667 }
668
669 # Returns a list of all used ids for a zone
670 zone_config_list_ids() {
671 assert [ $# -eq 1 ]
672
673 local zone=${1}
674 local config
675 local ids
676
677 for config in $(zone_configs_list ${zone}); do
678 list_append ids "$(config_get_id_from_config ${config})"
679 done
680
681 echo ${ids}
682 }
683
684 # List all hids of a zone
685 zone_config_list_hids() {
686 assert [ $# -eq 1 ]
687
688 local zone=${1}
689
690 local config
691 for config in $(zone_configs_list ${zone}); do
692 zone_config_get_hid "${zone}" "${config}"
693 done
694 }
695
696 # get the hid from a given config
697 zone_config_get_hid() {
698 assert [ $# -eq 2 ]
699
700 local zone=${1}
701 local config=${2}
702
703 local hook="$(zone_config_get_hook "${zone}" "${config}")"
704
705 hook_exec "config" "${hook}" "hid" "${zone}" "${config}"
706 }
707
708 # Checks if a hid is valid for a given zone
709 zone_config_hid_is_valid() {
710 assert [ $# -eq 2]
711
712 local zone=${1}
713 local hid=${2}
714
715 local _hid
716 for _hid in $(zone_config_list_hids "${zone}"); do
717 if [[ ${_hid} = ${hid} ]]; then
718 return ${EXIT_TRUE}
719 fi
720 done
721
722 return ${EXIT_FALSE}
723 }
724
725 # This function converts a hid to a id
726 zone_config_convert_hid_to_id() {
727 assert [ $# -eq 2 ]
728
729 local zone=${1}
730 local hid=${2}
731
732 local config
733 for config in $(zone_configs_list ${zone}); do
734 # Get hook from config
735 local hook="$(zone_config_get_hook "${zone}" "${config}")"
736
737 if [[ "$(hook_exec "config" "${hook}" "hid" "${zone}" "${config}")" == "${hid}" ]]; then
738 config_get_id_from_config "${config}"
739 return ${EXIT_TRUE}
740 fi
741 done
742
743 return ${EXIT_FALSE}
744 }
745
746 zone_show() {
747 local zone=${1}
748
749 echo "${zone}"
750 echo " Type: $(zone_get_hook ${zone})"
751 echo
752 }
753
754 zones_show() {
755 local zone
756
757 for zone in $(zones_get $@); do
758 zone_show ${zone}
759 done
760 }
761
762 zones_get_all() {
763 local zone
764 for zone in $(zone_dir)/*; do
765 zone=$(basename ${zone})
766 zone_exists ${zone} || continue
767
768 echo "${zone}"
769 done
770 }
771
772 zones_get_next_free() {
773 # This function return the next free zones.
774 # Example net0 upl0 upl1 are configured so the next free zones are:
775 # net1 upl2
776 local i
777 local zone_name
778 for zone_name in ${VALID_ZONES}; do
779 i=0
780
781 while true; do
782 local zone="${zone_name}${i}"
783 if ! zone_exists ${zone}; then
784 echo "${zone}"
785 break
786 fi
787 i=$(( i + 1 ))
788 done
789 done
790 }
791
792 zones_get_local() {
793 local zone
794 for zone in $(zones_get_all); do
795 zone_is_local ${zone} && echo "${zone}"
796 done
797 }
798
799 zones_get_nonlocal() {
800 local zone
801 for zone in $(zones_get_all); do
802 zone_is_nonlocal ${zone} && echo "${zone}"
803 done
804 }
805
806 zones_get() {
807 local local=1
808 local remote=1
809
810 local zones
811
812 while [ $# -gt 0 ]; do
813 case "${1}" in
814 --local-only)
815 local=1
816 remote=0
817 ;;
818 --remote-only)
819 local=0
820 remote=1
821 ;;
822 --all)
823 local=1
824 remote=1
825 ;;
826 *)
827 if zone_name_is_valid ${1}; then
828 zones="${zones} ${1}"
829 else
830 warning "Unrecognized argument '${1}'"
831 fi
832 ;;
833 esac
834 shift
835 done
836
837 if [ -n "${zones}" ]; then
838 local zone
839 for zone in ${zones}; do
840 zone_exists ${zone} && echo "${zone}"
841 done
842 exit ${EXIT_OK}
843 fi
844
845 if [ ${local} -eq 1 ] && [ ${remote} -eq 1 ]; then
846 zones_get_all
847 elif [ ${local} -eq 1 ]; then
848 zones_get_local
849 elif [ ${remote} -eq 1 ]; then
850 zones_get_nonlocal
851 fi
852 }
853
854 zone_ports_list() {
855 local zone=${1}
856
857 local port
858 for port in $(zone_dir ${zone})/ports/*; do
859 [ -e "${port}" ] || continue
860
861 echo $(basename ${port})
862 done
863 }
864
865 zone_port_attach() {
866 local zone="${1}"
867 assert isset zone
868
869 local port="${2}"
870 assert isset port
871
872 shift 2
873
874 # Check if the port actually exists.
875 if ! port_exists "${port}"; then
876 error "Cannot attach port '${port}' which does not exist"
877 return ${EXIT_ERROR}
878 fi
879
880 # Check if the port is already connected to this or any other zone.
881 local z
882 for z in $(zones_get_all); do
883 if zone_has_port "${z}" "${port}"; then
884 error "Port '${port}' is already attached to zone '${z}'"
885 return ${EXIT_ERROR}
886 fi
887 done
888
889 local hook="$(zone_get_hook "${zone}")"
890 assert isset hook
891
892 # Make the port briefly flash if supported
893 if device_exists ${port}; then
894 port_identify "${port}" --background
895 fi
896
897 hook_zone_exec "${hook}" "port_attach" "${zone}" "${port}" "$@"
898 local ret="${?}"
899
900 case "${ret}" in
901 ${EXIT_OK})
902 log INFO "${port} has been attached to ${zone}"
903
904 # Automatically connect the port
905 zone_port_start "${zone}" "${port}"
906 ;;
907 *)
908 log CRITICAL "${port} could not be attached to ${zone}"
909 ;;
910 esac
911
912 return ${ret}
913 }
914
915 zone_port_edit() {
916 local zone="${1}"
917 assert isset zone
918
919 local port="${2}"
920 assert isset port
921
922 shift 2
923
924 # Check if the port actually exists.
925 if ! port_exists "${port}"; then
926 error "Port '${port}' does not exist"
927 return ${EXIT_ERROR}
928 fi
929
930 # Check if the zone actually has this port.
931 if ! zone_has_port "${zone}" "${port}"; then
932 error "Port '${port}' is not attached to zone '${zone}'"
933 return ${EXIT_ERROR}
934 fi
935
936 local hook=$(zone_get_hook "${zone}")
937 assert isset hook
938
939 hook_zone_exec "${hook}" "port_edit" "${zone}" "${port}" "$@"
940 }
941
942 zone_port_detach() {
943 local zone="${1}"
944 assert isset zone
945
946 local port="${2}"
947 assert isset port
948
949 shift 2
950
951 # Check if the zone actually has this port.
952 if ! zone_has_port "${zone}" "${port}"; then
953 error "Port '${port}' is not attached to zone '${zone}'"
954 return ${EXIT_ERROR}
955 fi
956
957 local hook=$(zone_get_hook "${zone}")
958 assert isset hook
959
960 # Make the port briefly flash if supported
961 port_identify "${port}" --background
962
963 hook_zone_exec "${hook}" "port_detach" "${zone}" "${port}" "$@"
964 local ret="${?}"
965
966 case "${ret}" in
967 ${EXIT_OK})
968 log INFO "${port} has been detached from ${zone}"
969
970 # Bring down the port if needed
971 zone_port_stop "${zone}" "${port}"
972 ;;
973 *)
974 log CRITICAL "${port} could not be detached from ${zone}"
975 ;;
976 esac
977
978 return ${ret}
979 }
980
981 zone_port_cmd() {
982 local cmd="${1}"
983 assert isset cmd
984
985 local zone="${2}"
986 assert isset zone
987
988 local port="${3}"
989 assert isset port
990
991 shift 3
992
993 local hook="$(zone_get_hook "${zone}")"
994 assert isset hook
995
996 # Dispatch command to hook
997 hook_zone_exec "${hook}" "${cmd}" "${zone}" "${port}" $@
998 }
999
1000 zone_port_create() {
1001 zone_port_cmd "port_create" $@
1002 }
1003
1004 zone_port_remove() {
1005 zone_port_cmd "port_remove" $@
1006 }
1007
1008 zone_port_up() {
1009 zone_port_cmd "port_up" $@
1010 }
1011
1012 zone_port_down() {
1013 zone_port_cmd "port_down" $@
1014 }
1015
1016 # The next two functions automagically bring up and down
1017 # port that are attached to a bridge or similar.
1018 # The problem that is tried to overcome here is that there
1019 # are ports which exist all the time (like ethernet ports)
1020 # and therefore do not dispatch a hotplug event when
1021 # port_create is called.
1022
1023 zone_port_start() {
1024 local zone="${1}"
1025 local port="${2}"
1026
1027 if zone_is_active "${zone}"; then
1028 if device_exists "${port}"; then
1029 zone_port_up "${zone}" "${port}"
1030 return ${?}
1031 else
1032 zone_port_create "${zone}" "${port}"
1033 return ${?}
1034 fi
1035 fi
1036
1037 return ${EXIT_OK}
1038 }
1039
1040 zone_port_stop() {
1041 local zone="${1}"
1042 local port="${2}"
1043
1044 # Shut down the port if necessary
1045 if zone_is_active "${zone}" && port_is_up "${port}"; then
1046 zone_port_down "${zone}" "${port}"
1047 fi
1048
1049 # Remove the port
1050 zone_port_remove "${zone}" "${port}"
1051 }
1052
1053 zone_port_status() {
1054 zone_port_cmd "port_status" $@
1055 }
1056
1057 zone_ports_cmd() {
1058 local cmd="${1}"
1059 assert isset cmd
1060
1061 local zone="${2}"
1062 assert isset zone
1063
1064 shift 2
1065
1066 local hook="$(zone_get_hook "${zone}")"
1067
1068 local port
1069 for port in $(zone_get_ports ${zone}); do
1070 hook_zone_exec "${hook}" "${cmd}" "${zone}" "${port}" $@
1071 done
1072 }
1073
1074 zone_ports_create() {
1075 zone_ports_cmd "port_create" $@
1076 }
1077
1078 zone_ports_remove() {
1079 zone_ports_cmd "port_remove" $@
1080 }
1081
1082 zone_ports_up() {
1083 zone_ports_cmd "port_up" $@
1084 }
1085
1086 zone_ports_down() {
1087 zone_ports_cmd "port_down" $@
1088 }
1089
1090 zone_ports_status() {
1091 zone_ports_cmd "port_status" $@
1092 }
1093
1094 zone_configs_cmd() {
1095 assert [ $# -ge 2 ]
1096
1097 local cmd="${1}"
1098 local zone="${2}"
1099 shift 2
1100
1101 assert zone_exists "${zone}"
1102
1103 local config
1104 for config in $(zone_configs_list "${zone}"); do
1105 local config_hook="$(zone_config_get_hook "${zone}" "${config}")"
1106 assert isset config_hook
1107
1108 hook_config_exec "${config_hook}" "${cmd}" "${zone}" "${config}" $@
1109 done
1110 }
1111
1112 zone_configs_up() {
1113 zone_configs_cmd "up" $@
1114 }
1115
1116 zone_configs_down() {
1117 zone_configs_cmd "down" $@
1118 }
1119
1120 zone_configs_status() {
1121 zone_configs_cmd "status" $@
1122 }
1123
1124 zone_configs_list() {
1125 local zone=${1}
1126
1127 local config
1128 for config in $(zone_dir ${zone})/configs/*; do
1129 [ -e "${config}" ] || continue
1130
1131 basename ${config}
1132 done
1133 }
1134
1135 zone_config_get_new_id() {
1136 # This functions returns the next free id for a zone
1137
1138 assert [ $# -eq 1 ]
1139 local zone=${1}
1140
1141 local zone_path=$(zone_dir ${zone})
1142 local i=0
1143
1144 while true; do
1145 if [ ! -f ${zone_path}/configs/*.${i} ]; then
1146 echo "${i}"
1147 return ${EXIT_OK}
1148 fi
1149 (( i++ ))
1150 done
1151 }
1152
1153 zone_config_check_same_setting() {
1154 # This functions checks if a config hook
1155 # with the same setting is already configured for this zone.
1156 # Returns True when yes and False when no.
1157
1158 assert [ $# -eq 4 ]
1159
1160 local zone=${1}
1161 local hook=${2}
1162 local key=${3}
1163 local value=${4}
1164
1165 # The key should be local for this function
1166 local ${key}
1167 local config
1168
1169 for config in $(zone_configs_list ${zone}); do
1170 # Check if the config is from the given hook, when not continue
1171 if [[ $(zone_config_get_hook "${zone}" "${config}") != ${hook} ]]; then
1172 continue
1173 fi
1174 # Get the value of the key for a given function
1175 zone_config_settings_read "${zone}" "${config}" \
1176 --ignore-superfluous-settings "${key}"
1177 # Check if the value of the config and the passed value are eqal
1178 if [[ "${value}" == "${!key}" ]]; then
1179 return ${EXIT_TRUE}
1180 fi
1181 done
1182
1183 return ${EXIT_FALSE}
1184 }
1185
1186 zone_config_get_hook() {
1187 assert [ $# -eq 2 ]
1188
1189 local zone="${1}"
1190 assert isset zone
1191
1192 local config="${2}"
1193 assert isset config
1194
1195 local HOOK
1196 zone_config_settings_read "${zone}" "${config}" \
1197 --ignore-superfluous-settings HOOK
1198
1199 print "${HOOK}"
1200 }
1201
1202 zone_config_hook_is_configured() {
1203 # Checks if a zone has already at least one config with the given hook.
1204 # Returns True when yes and False when no
1205
1206 assert [ $# -eq 2 ]
1207 local zone=${1}
1208 local hook=${2}
1209
1210 local config
1211 for config in $(zone_configs_list "${zone}"); do
1212 local config_hook="$(zone_config_get_hook "${zone}" "${config}")"
1213 assert isset config_hook
1214 if [[ ${hook} == ${config_hook} ]]; then
1215 return ${EXIT_TRUE}
1216 fi
1217
1218 done
1219
1220 # If we get here the zone has no config with the given hook
1221 return ${EXIT_FALSE}
1222 }
1223
1224 zone_config_id_is_valid() {
1225 # This function checks if a given id is valid for a zone
1226 # Return True when yes and false when no
1227
1228 assert [ $# -eq 2 ]
1229 local zone=${1}
1230 local id=${2}
1231
1232 local zone_path=$(zone_dir ${zone})
1233
1234 [ -f ${zone_path}/configs/*.${id} ];
1235 }
1236
1237 # This function checks if a given hid is valid for a zone
1238 # Return True when yes and false when no
1239 zone_config_hid_is_valid() {
1240 assert [ $# -eq 2 ]
1241 local zone=${1}
1242 local hid=${2}
1243
1244 local _hid
1245 for _hid in $(zone_config_list_hids ${zone}); do
1246 if [[ ${_hid} == ${hid} ]]; then
1247 return ${EXIT_TRUE}
1248 fi
1249 done
1250
1251 return ${EXIT_FALSE}
1252 }
1253
1254 zone_config_get_hook_from_id() {
1255 # Returns the hook for a given id
1256 assert [ $# -eq 2 ]
1257 local zone=${1}
1258 local id=${2}
1259
1260 local config
1261 for config in $(zone_configs_list "${zone}"); do
1262 if [[ ${config} == *.${id} ]]; then
1263 local config_hook="$(zone_config_get_hook "${zone}" "${config}")"
1264 assert isset config_hook
1265 print "${config_hook}"
1266 return "${EXIT_OK}"
1267 fi
1268 done
1269
1270 # If we get here the zone has no config with the given id
1271 return ${EXIT_ERROR}
1272 }
1273
1274 zone_has_ip() {
1275 device_has_ip $@
1276 }
1277
1278 zone_db() {
1279 local zone=${1}
1280 local action=${2}
1281 shift 2
1282
1283 case "${action}" in
1284 starting|started|stopping|stopped)
1285 db_connection_update ${zone} ${action}
1286 ;;
1287 esac
1288 }
1289
1290 zone_is_up() {
1291 local zone=${1}
1292
1293 device_is_up ${zone}
1294 }
1295
1296 zone_is_down() {
1297 ! zone_is_up $@
1298 }
1299
1300 zone_get_supported_port_hooks() {
1301 local zone=${1}
1302
1303 local hook=$(zone_get_hook ${zone})
1304
1305 hook_zone_ports_get_all ${hook}
1306 }
1307
1308 zone_get_supported_config_hooks() {
1309 hook_config_get_all
1310 }
1311
1312 zone_file() {
1313 local zone=${1}
1314
1315 assert isset zone
1316
1317 echo "$(zone_dir ${zone})/settings"
1318 }
1319
1320 zone_settings_read() {
1321 local zone=${1}
1322 assert isset zone
1323 shift
1324
1325 local args
1326 if [ $# -eq 0 ] && [ -n "${HOOK_SETTINGS}" ]; then
1327 list_append args ${HOOK_SETTINGS}
1328 else
1329 list_append args $@
1330 fi
1331
1332 # Save the HOOK variable.
1333 local hook="${HOOK}"
1334
1335 settings_read "$(zone_file "${zone}")" ${args}
1336
1337 # Restore hook.
1338 HOOK="${hook}"
1339 }
1340
1341 zone_settings_write() {
1342 local zone="${1}"
1343 assert isset zone
1344
1345 local args
1346 if function_exists "hook_check_settings"; then
1347 list_append args "--check=\"hook_check_settings\""
1348 fi
1349 list_append args ${HOOK_SETTINGS}
1350
1351 settings_write "$(zone_file ${zone})" ${args}
1352 }
1353
1354 zone_settings_set() {
1355 local zone=${1}
1356 shift
1357 local args="$@"
1358
1359 assert isset zone
1360
1361 (
1362 zone_settings_read ${zone}
1363
1364 for arg in ${args}; do
1365 eval "${arg}"
1366 done
1367
1368 zone_settings_write ${zone}
1369 )
1370 }
1371
1372 zone_settings_get() {
1373 local zone=${1}
1374 local key=${2}
1375
1376 assert isset zone
1377 assert isset key
1378
1379 (
1380 zone_settings_read "${zone}" "${key}" \
1381 --ignore-superfluous-settings
1382
1383 echo "${!key}"
1384 )
1385 }
1386
1387 zone_config_settings_read() {
1388 assert [ $# -ge 2 ]
1389
1390 local zone="${1}"
1391 local config="${2}"
1392 shift 2
1393
1394 local args
1395 if [ $# -eq 0 ] && [ -n "${HOOK_CONFIG_SETTINGS}" ]; then
1396 list_append args ${HOOK_CONFIG_SETTINGS}
1397 else
1398 list_append args $@
1399 fi
1400
1401 local path="$(zone_dir "${zone}")/configs/${config}"
1402 settings_read "${path}" ${args}
1403 }
1404
1405 zone_config_settings_write() {
1406 assert [ $# -ge 2 ]
1407
1408 local zone="${1}"
1409 local hook="${2}"
1410 local id=${3}
1411
1412 if ! isset id; then
1413 id=$(zone_config_get_new_id ${zone})
1414 log DEBUG "ID for the config is: ${id}"
1415 fi
1416
1417 local args
1418 if function_exists "hook_check_config_settings"; then
1419 list_append args "--check=\"hook_check_config_settings\""
1420 fi
1421 list_append args ${HOOK_CONFIG_SETTINGS}
1422
1423 local path="$(zone_dir "${zone}")/configs/${hook}.${id}"
1424 settings_write "${path}" ${args}
1425 }
1426
1427 zone_config_settings_destroy() {
1428 # This function deletes the config file for a given zone and config
1429 assert [ $# -ge 2 ]
1430 local zone="${1}"
1431 local config="${2}"
1432
1433 local path="$(zone_dir "${zone}")/configs/${config}"
1434
1435 # Check if path is valid
1436 if [ ! -f ${path} ]; then
1437 log ERROR "Path: '${path}' is not valid"
1438 return ${EXIT_ERROR}
1439 fi
1440
1441 log DEBUG "Deleting config file ${path}"
1442 rm -f "${path}"
1443
1444 }
1445 zone_port_settings_read() {
1446 assert [ $# -ge 2 ]
1447
1448 local zone="${1}"
1449 local port="${2}"
1450 shift 2
1451
1452 local args
1453 if [ $# -eq 0 ] && [ -n "${HOOK_PORT_SETTINGS}" ]; then
1454 list_append args ${HOOK_PORT_SETTINGS}
1455 else
1456 list_append args $@
1457 fi
1458
1459 local path="$(zone_dir "${zone}")/ports/${port}"
1460 settings_read "${path}" ${args}
1461 }
1462
1463 zone_port_settings_write() {
1464 assert [ $# -ge 2 ]
1465
1466 local zone="${1}"
1467 local port="${2}"
1468 shift 2
1469
1470 local args
1471 if function_exists "hook_check_port_settings"; then
1472 list_append args "--check=\"hook_check_port_settings\""
1473 fi
1474 list_append args ${HOOK_PORT_SETTINGS}
1475
1476 local path="$(zone_dir "${zone}")/ports/${port}"
1477 settings_write "${path}" ${args}
1478 }
1479
1480 zone_port_settings_remove() {
1481 assert [ $# -eq 2 ]
1482
1483 local zone="${1}"
1484 local port="${2}"
1485
1486 local path="$(zone_dir "${zone}")/ports/${port}"
1487 settings_remove "${path}"
1488 }
1489
1490 zone_get_color() {
1491 # This function return the color of a zone
1492 assert [ $# -eq 1 ]
1493
1494 local name=${1}
1495 color_read "zone" ${name}
1496 }
1497
1498 zone_get_description_title() {
1499 assert [ $# -eq 1 ]
1500
1501 local name=${1}
1502 description_title_read $(description_format_filename "zone" "${name}")
1503 }