1#!/usr/bin/awk -f
2#-
3# Copyright (c) 2017 G. Paul Ziemba
4# All rights reserved.
5#
6#  Redistribution and use in source and binary forms, with or without
7#  modification, are permitted provided that the following conditions
8#  are met:
9#  1. Redistributions of source code must retain the above copyright
10#     notice, this list of conditions and the following disclaimer.
11#  2. Redistributions in binary form must reproduce the above copyright
12#     notice, this list of conditions and the following disclaimer in the
13#     documentation and/or other materials provided with the distribution.
14#
15#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16#  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18#  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25#  SUCH DAMAGE.
26#
27# $FreeBSD$
28#
29
30#
31# /etc/autofs/include_nis_nullfs
32#
33# automountd Directory Services script for NIS
34#
35# SYNOPSIS
36#       include_nis_nullfs <mapname>
37#
38#       include_nis_nullfs <mapname> <key>
39#
40# DESCRIPTION
41#
42#       This script provides a Directory Services map for automountd
43#       based on NIS. Please see auto_master(5) for general information.
44#
45#       The first form, with one argument, emits the entire named NIS map.
46#       The second form, with two arguments, emits the map entry for the
47#       key given in the second argument.
48#
49#       This script attempts to determine the names and IP addresses
50#       of the local host. Map entries matching the local host are
51#       rewritten to specify nullfs mounts (instead of the default
52#       NFS) to reduce access overhead in the kernel.
53#
54#	If a map entry contains multiple location fields, it is not changed.
55#
56
57
58# Populate list of names and IP addrs thet mean "this host"
59# into myhostnames array
60BEGIN {
61    #
62    # Set self hostnames
63    #
64
65    "hostname -s" | getline;
66    myhostnames[$0] = 1;
67
68    "hostname -f" | getline;
69    myhostnames[$0] = 1;
70
71    myhostnames["localhost"] = 1
72
73    "hostname -f" | getline;
74    localdomain=$0
75    myhostnames["localhost."localdomain] = 1
76
77    while ("ifconfig" | getline) {
78	if ($1 == "inet") {
79	    myhostnames[$2] = 1;
80	}
81    }
82
83    # debug
84#            print "--- hostname list start ----"
85#            for (i in myhostnames) {
86#                print i
87#            }
88#            print "--- hostname list end ----"
89
90    if (ARGC == 2) {
91	# mapname only
92	while ("ypcat -k " ARGV[1] | getline) {
93	    proc_mapline(1)
94	}
95    }
96    if (ARGC == 3) {
97	# mapname and keyname
98	while ("ypmatch " ARGV[2] " " ARGV[1] | getline) {
99	    proc_mapline(0)
100	}
101    }
102    exit 0
103}
104
105function is_self(hostname)
106{
107    if (myhostnames[hostname]) {
108	return 1
109    }
110    return 0
111}
112
113#
114# Lines are of the form [key] [-opts] location1 [... locationN]
115#
116# indicate index of key field with first positional parameter
117# 1 means keyfield is the first field
118# 0 means keyfield is not present
119#
120function proc_mapline(keyfield)
121{
122    optionsfield = 0
123    locationfield = 0
124    locationcount = 0
125
126    for (i=keyfield+1; i <= NF; ++i) {
127	if (!optionsfield) {
128	    if ($i ~ /^-/) {
129		# the first options field found on the line
130		optionsfield = i;
131		continue
132	    }
133	}
134	# Assumption: location contains colon (":")
135	if (optionsfield && ($i ~ /:/) && ($i !~ /^-/)) {
136	    ++locationcount
137	    if (!locationfield) {
138		# the first location field found on the line
139		locationfield = i
140	    }
141	}
142    }
143
144    #
145    # If location not found, do not modify.
146    #
147    # If there is more than one location, do not modify. Rationale:
148    # Options are applied to all locations. We ca not have "nullfs"
149    # for only some locations and "nfs" for others for a given
150    # map key (i.e., a line). The usual reason for multiple
151    # locations is for redundancy using replicated volumes on
152    # multiple hosts, so multiple hosts imply fstype=nfs (the
153    # FreeBSD default for automounter maps).
154    #
155    # Hypothetically there could be a map entry with multiple
156    # locations all with host parts matching "me". In that case,
157    # it would be safe to rewrite the locations and specify
158    # nullfs, but the code does not handle this case.
159    #
160    if (locationcount == 1) {
161	#
162	# We have a line with exactly one location field
163	#
164	# Assumption: location has no more than one colon (":")
165	#
166	n=split($locationfield,location,":")
167	if (is_self(location[1])) {
168	    $locationfield = ":" location[2]
169	    if (optionsfield) {
170		# append to existing options
171		$optionsfield = $optionsfield ",fstype=nullfs"
172	    } else {
173		# sneak in ahead of location
174		$locationfield = "-fstype=nullfs " $locationfield
175	    }
176	}
177    }
178
179    print
180}
181