summaryrefslogtreecommitdiff
path: root/_NetBSD-pkgdb
blob: 03fc5b54e2e2e0d95f02db9909ee4be8b87454e4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
#!/bin/sh
# $NetBSD: _NetBSD-pkgdb,v 1.1 2020/12/28 01:18:27 gdt Exp $
# Copyright The NetBSD Foundation 2020

# This script is for NetBSD only.

# This script is intended to help with the process of migration of
# PKG_DBDIR from /var/db/pkg to /usr/pkg/pkgdb on NetBSD.  It can:
#
#   "check" the system, changing nothing
#
#   "fix" the system, leaving PKG_DBDIR as is and setting config files
#   to point to it.  Thus, one can easily postpone migration.
#
#   "migrate" the system, moving the contents of PKG_DBDIR to the new
#   location, and then setting pointers.
#
# In all cases, the script attempts to check assumptions it makes, and
# avoid trouble if those assumptions are not true.

# Note that PKG_DBDIR can be set in multiple places:
#   /etc/pkg_install.conf (base tools)
#   /usr/pkg/etc/pkg_install.conf (pkg tools)
#   /etc/mk.conf (variable when buidling)
#   /usr/pkgsrc/mk/ (default value of variable)

# This script takes the position that the PKG_DBDIR should be
# explicitly configured in pkg_install.conf in all cases, even if this
# is provably not necessary.  The theory is that a bit of explicit
# config is much less work than mysterious debugging.  If you don't
# like this, you are welcome to undo it, only use "check", or do the
# migration (or not) by hand.

# This script is aimed at the common case where the database was in
# /var/db/pkg and is moving to /usr/pkg/pkgdb, and sources are in
# /usr/pkgsrc (or a place that /usr/pkgsrc is symlinked to).

# This script should work to fix/migrate even on systems with older
# pkgsrc, e.g. if one wanted to stay on 2020Q3 on a system where the
# base system tools were updated.  "Fix" will set variables so
# everything should work correctly.

# The script is designed to do incremental fixes, so if you migrate by
# hand but do not patch up the refcount directory, or set variables,
# it should (NB: This is UNTESTED!) do those steps when run.

# The script is intentionally written to be easy to understand (as
# long as one is comfortable with shell functions), rather than
# compact, avoid repeated code, or elegant.

# This script assumes:
#   NetBSD 8 or newer
#   pkgsrc after about 2020-12-20 (including 2020Q4)
#   pkgsrc PREFIX as /usr/pkg
#   old PKG_DBDIR as /var/db/pkg
#   new/future PKG_DBDIR as /usr/pkg
#   no symlinks in old or new PKG_DBDIR location
#   base pkg_install may be old, or may be after the 2020-12 commit/pullups
#   pkgsrc sources, if they exist, are in /usr/pkgsrc (perhaps a symlink)

# Set pathnames.  Do not expect to set these differently without
# significant testing and thought.
OLDDB=/var/db/pkg
NEWDB=/usr/pkg/pkgdb
CONF_BASE=/etc/pkg_install.conf
CONF_PKG=/usr/pkg/etc/pkg_install.conf
PKGSRC=/usr/pkgsrc

# Shell functions to print messages of varying severity.  (We choose
# to avoid fancy formatting entirely in this script.)
msg () {
    echo "$*" >&2
}

warn () {
    echo "WARNING: $*" >&2
}

fatal () {
    echo "FATAL: $*" >&2
    exit 1
}

usage () {
    msg "_NetBSD-pkgdb: Usage:"
    msg "    check     Check pkgdb status and explain it."
    msg "    fix       Point config files at pkgdb location (don't move it)."
    msg "    migrate   Check if migration can be done automatically, and if so do it."
    exit 1
}

# Count problems.  (Be sure not to use subshells when calling this.)
problems=0
problem_pp () {
    problems=`expr $problems + 1`

}
problem_count () {
    echo $problems
}

dir_exists () {
    if [ ! -h "$1" -a -d "$1" ]; then
	echo true
    else
	echo false
    fi
}

# require_match string bool1 bool2
require_match () {
    if [ "$2" != "$3" ]; then
	fatal "mismatch $1"
	problem_pp
    fi
}

# Read pkg_install.conf PKG_DBDIR.  One arg: config file
get_pkg_install_conf_DBDIR () {
    CONF=$1
    if [ "${CONF}" = "" ]; then
	fatal "missing argument"
	# dead code, left in case error is removed
	echo ""
    elif [ ! -f ${CONF} ]; then
	warn "${CONF} does not exist"
	echo ""
    else
	line=`egrep "^PKG_DBDIR.*=" ${CONF}`
	if [ "$line" = "" ]; then
	    warn "${CONF} does not set PKG_DBDIR"
	    echo ""
	else
	    value=`echo $line | awk -F= '{print $2}'`
	    echo $value
	fi
    fi
}

# Ensure prerequisites.
do_prereq () {
    if [ `uname` != "NetBSD" ];then
	fatal "OS is not NetBSD"
    fi

    # Check a subdir, in case /usr/pkg is a symlink.
    if [ ! -d /usr/pkg/bin ]; then
	fatal "/usr/pkg/bin is not a directory"
    fi
}

# Check and maybe fix or migrate, depending on if fix=true or
# migrate=true.   migrate=true and fix=false is not allowed.
do_steps () {
    ## STEP 0: Check if it is ok to operate at all.
    do_prereq

    ## STEP 1: Sanity check database and figure out where it is.
    # See if old or new exists, and check that they are in pairs.
    OLD_DB1=`dir_exists ${OLDDB}`
    OLD_DB2=`dir_exists ${OLDDB}.refcount`
    require_match "$OLDDB directory pair" $OLD_DB1 $OLD_DB2
    NEW_DB1=`dir_exists ${NEWDB}`
    NEW_DB2=`dir_exists ${NEWDB}.refcount`
    require_match "$NEWDB directory pair" $NEW_DB1 $NEW_DB2

    # Check that we have one PKG_DBDIR, not zero and not two
    if [ "$OLD_DB1" = false -a "$NEW_DB1" = false ]; then
	fatal "No PKG_DBDIR found"
	problem_pp
    fi
    if [ "$OLD_DB1" = true -a "$NEW_DB1" = true ]; then
	fatal "TWO copies of PKG_DBDIR found"
	problem_pp
    fi

    # Set a variable to the DBDIR we should be using, and the one we aren't.
    if [ "$OLD_DB1" = true ]; then
	PKG_DBDIR=$OLDDB
	PKG_DBDIR_NOT=$NEWDB
    elif [ "$NEW_DB1" = true ]; then
	PKG_DBDIR=$NEWDB
	PKG_DBDIR_NOT=$OLDDB
    else
	fatal "LOGIC ERROR IN SCRIPT 001"
	exit 1
    fi
    unset OLD_DB1
    unset OLD_DB2
    unset NEW_DB1
    unset OLD_DB2
    echo "Found PKG_DBDIR as $PKG_DBDIR."

    ## Step 2a: check migrate/fix prereqs
    if [ "$fix" = true ]; then
	warn "THIS SCRIPT IS NOT YET ADEQUATELY TESTED."
	warn "Hit ^C NOW if you do not have a good backup."
	warn "Proceeding in 10 seconds..."
	sleep 10

	if [ `id -u` != 0 ]; then
	    fatal "Not root: will not be able to fix or migrate"
	fi
    fi

    ## Step 2: migrate if requested
    if [ "$migrate" = true ]; then
	if [ "$fix" != true ]; then
	    fatal "LOGIC ERROR IN SCRIPT 002"
	fi
	
	if [ "$PKG_DBDIR" = "${NEWDB}" ]; then
	    warn "migrate requested when already done"
	    # This is not really an error.
	else
	    msg "Doing migration..."
	    msg "NB: refcount will have many fixups; this is normal."

	    # Actual migration is easy.
	    mv $OLDDB $NEWDB
	    mv $OLDDB.refcount $NEWDB.refcount

	    # Change our tracking variables so that later fixups do
	    # the right thing.
	    PKG_DBDIR=$NEWDB
	    PKG_DBDIR_NOT=$OLDDB

	    msg "Migration done, except for refcount fixups."
	fi
    fi

    ## Step 3: Check/fix refcount
    if [ "$fix" = true ]; then
	# Check all files, even though only some have paths.
	find ${PKG_DBDIR}.refcount -type f | while read file; do
	    if egrep $PKG_DBDIR_NOT $file > /dev/null; then
		echo WRONG PATH $file
		sed -i -e "s,${PKG_DBDIR_NOT},${PKG_DBDIR}," $file
		problem_pp
	    fi
	done
    fi
    
    ## Step 4: Check PKG_DBDIR variables and fix if requested.
    # Check that both pkg_install configs point to the actual PKG_DBDIR.
    conf_base_DBDIR=`get_pkg_install_conf_DBDIR $CONF_BASE`
    if [ "$conf_base_DBDIR" != "${PKG_DBDIR}" ]; then
	warn "$CONF_BASE does not set PKG_DBDIR to ${PKG_DBDIR}"
	if [ "$fix" = true ]; then
	    [ -f ${CONF_BASE} ] && cp -p ${CONF_BASE} ${CONF_BASE}.pre-migration
	    sed -i -e '/^PKG_DBDIR=/d' ${CONF_BASE}
	    echo "PKG_DBDIR=${PKG_DBDIR}" >> ${CONF_BASE}
	fi
	problem_pp
    fi
    conf_pkg_DBDIR=`get_pkg_install_conf_DBDIR $CONF_PKG`
    if [ "$conf_pkg_DBDIR" != "${PKG_DBDIR}" ]; then
	warn "$CONF_PKG does not set PKG_DBDIR to ${PKG_DBDIR}"
	if [ "$fix" = true ]; then
	    [ -f ${CONF_PKG} ] && cp -p ${CONF_PKG} ${CONF_PKG}.pre-migration
	    sed -i -e '/^PKG_DBDIR=/d' ${CONF_PKG}
	    echo "PKG_DBDIR=${PKG_DBDIR}" >> ${CONF_PKG}
	fi
	problem_pp
    fi

    # Check mk.conf via pkgsrc.  Really, check that the variable is
    # set when running in an example package, because it is relatively
    # normal to use .include and we decline to re-implement make.
    if [ -d ${PKGSRC}/mk ]; then
	# Avoid a subshell so problem_pp works.
	SAVE=`pwd`
	cd $PKGSRC
	PKGSRC_DBDIR=`cd devel/m4 && make show-var VARNAME=PKG_DBDIR`
	if [ "$PKGSRC_DBDIR" != "${PKG_DBDIR}" ]; then
	    warn "$PKG_DBDIR via pkgsrc/mk does not set PKG_DBDIR to ${PKG_DBDIR}"
	    # This may have failed for other reasons, but if so running again won't
	    # fix it.
	    if [ "$fix" = true ]; then
		sed -i -e '/^PKG_DBDIR=/d' /etc/mk.conf
		echo "PKG_DBDIR=${PKG_DBDIR}" >> /etc/mk.conf
	    fi
	    problem_pp
	fi
	cd $SAVE
	unset SAVE
    else
	msg "NB: Did not find ${PKGSRC} -- did not check mk.conf"
	msg "    If your system does not have sources, this is ok.  If it does, symlink"
	msg "    ${PKGSRC} to the sources and rerun the check."
    fi
}
    
main() {
    if [ "$#" != 1 ]; then
	usage
    fi
    
    case "$1" in
	check)
	    do_steps
	    ;;
	fix)
	    fix=true;
	    do_steps
	    ;;
	migrate)
	    fix=true
	    migrate=true;
	    do_steps
	    ;;
	*)
	    warn Unknown option $1
	    usage
	    ;;
    esac

    count=`problem_count`
    if [ "$count" = 0 ]; then
	msg "No problems found."
    else
	msg "TOTAL PROBLEMS FOUND: $count"
	msg "Re-run script until there are no problems!"
    fi
}

main $*