b02deed1c7888ef45a2453c972df3bc9d2fccc89
[pkgsrcv2.git] / pkgtools / pkg_chk / files / pkg_chk.sh
1 #!@SH@ -e
2 #
3 # $Id: pkg_chk.sh,v 1.65 2009/07/22 21:56:13 sketch Exp $
4 #
5 # TODO: Make -g check dependencies and tsort
6 # TODO: Make -g list user-installed packages first, followed by commented
7 #       out automatically installed packages
8 # TODO: List user-installed packages that are not in config
9
10 PATH=${PATH}:/usr/sbin:/usr/bin
11
12 SUMMARY_FILE=pkg_summary.gz
13 OLD_SUMMARY_FILE=pkg_chk-summary
14
15 is_binary_available()
16     {
17     if [ -n "$PKGDB" ]; then
18         for iba_pkg in $PKGDB; do
19             case $iba_pkg in
20                 *:"$1")
21                     return 0;
22                 ;;
23             esac
24         done
25         return 1;
26     else
27         if [ -f "$PACKAGES/$1$PKG_SUFX" ]; then
28             return 0;
29         else
30             return 1;
31         fi
32     fi
33     }
34
35 bin_pkg_info2pkgdb()
36     {
37     ${AWK} '/^PKGNAME=/ {sub("^PKGNAME=", ""); PKGNAME=$0} \
38             /^PKGPATH=/ {sub("^PKGPATH=", ""); printf("%s:%s ", $0, PKGNAME)}'
39     }
40
41 check_packages_installed()
42     {
43     MISSING_TODO=
44     MISMATCH_TODO=
45
46     for pkgdir in $* ; do
47
48         if [ -n "$opt_B" ];then
49             extract_pkg_vars $pkgdir PKGNAME FILESDIR PKGDIR DISTINFO_FILE PATCHDIR
50         elif [ -n "$opt_s" ] ; then
51             extract_pkg_vars $pkgdir PKGNAME
52         else
53             PKGNAME=`pkgdir2pkgname $pkgdir`
54         fi
55         if [ -z "$PKGNAME" ]; then
56             MISS_DONE=$MISS_DONE" "$pkgdir
57             continue
58         fi
59         if [ ! -d $PKG_DBDIR/$PKGNAME ];then
60             msg_n "$pkgdir - "
61             pkg=$(echo $PKGNAME | ${SED} 's/-[0-9].*//')
62             pkginstalled=$(sh -c "${PKG_INFO} -e $pkg" || true)
63             INSTALL=
64             if [ -n "$pkginstalled" ];then
65                 msg_n "$pkginstalled < $PKGNAME"
66                 MISMATCH_TODO="$MISMATCH_TODO $pkginstalled"
67             else
68                 msg_n "$PKGNAME missing"
69                 MISSING_TODO="$MISSING_TODO $PKGNAME $pkgdir"
70             fi
71             if is_binary_available $PKGNAME ;then
72                 msg_n " (binary package available)"
73             fi
74             msg
75         else
76             if [ -n "$opt_B" ];then
77                 # sort here temporarily to handle older +BUILD_VERSION
78                 current_build_ver=$(get_build_ver | ${SED} 's|.*\$Net''BSD\: ||' | ${SORT} -u)
79                 installed_build_ver=$(${SED} 's|.*\$Net''BSD\: ||' $PKG_DBDIR/$PKGNAME/+BUILD_VERSION | ${SORT} -u)
80                 if [ x"$current_build_ver" != x"$installed_build_ver" ];then
81                     msg "$pkgdir - $PKGNAME build_version mismatch"
82                     verbose "--current--"
83                     verbose "$current_build_ver"
84                     verbose "--installed--"
85                     verbose "$installed_build_ver"
86                     verbose "----"
87                     MISMATCH_TODO="$MISMATCH_TODO $PKGNAME"
88                 else
89                     verbose "$PKGNAME: OK"
90                 fi
91             else
92                 verbose "$PKGNAME: OK"
93             fi
94         fi
95     done
96     }
97
98 cleanup_and_exit()
99     {
100     rm -f $MY_TMPFILE
101     rmdir $MY_TMPDIR
102     exit "$@"
103     }
104
105 delete_pkgs()
106     {
107     for pkg in $* ; do
108         if [ -d $PKG_DBDIR/$pkg ] ; then
109             run_cmd_su "${PKG_DELETE} -r $pkg" 1
110         fi
111     done
112     }
113
114 extract_make_vars()
115     {
116     MAKEFILE=$1
117     shift
118     MAKEDATA=".PHONY: x\nx:\n";
119     for var in $* ; do
120         MAKEDATA=$MAKEDATA"\t@echo $var=\${$var}\n"
121     done
122     eval $(printf "$MAKEDATA" | ${MAKE} -f - -f $MAKEFILE x | \
123                                         ${SED} -e 's/[^=]*=/&"/' -e 's/$/"/')
124     for var in $* ; do
125         verbose_var $var
126     done
127     }
128
129 # $1 = name of variable
130 # $2 = default value
131 extract_mk_var()
132     {
133     if [ -z "`eval echo \\$$1`" ] ; then
134         eval $(printf "BSD_PKG_MK=1\n.PHONY: x\nx:\n\t@echo $1="'$'"{$1}\n" | ${MAKE} -f - -f $MAKECONF x)
135         if [ -z "`eval echo \\$$1`" ]; then
136             eval "$1=$2"
137             verbose_var $1 '(using default)'
138         else
139             verbose_var $1
140         fi
141     fi
142     }
143
144 extract_pkg_vars()
145     {
146     PKGDIR=$1
147     PKGNAME=
148     shift;
149     if [ ! -f $PKGSRCDIR/$pkgdir/Makefile ];then
150         msg "WARNING: No $pkgdir/Makefile - package moved or obsolete?"
151         return
152     fi
153     cd $PKGSRCDIR/$PKGDIR
154     extract_make_vars Makefile "$@"
155     if [ -z "$PKGNAME" ]; then
156         fatal "Unable to extract PKGNAME for $pkgdir"
157     fi
158     }
159
160 extract_variables()
161     {
162     extract_mk_var PKGSRCDIR ''
163     extract_mk_var LOCALBASE ''
164     if [ -z "$PKGSRCDIR" ] ; then
165         for dir in $LOCALBASE/pkgsrc /usr/pkgsrc . .. ../.. ; do
166             if [ -f "${dir}/mk/bsd.pkg.mk" ]; then
167                 case "${dir}" in
168                 /*) PKGSRCDIR="${dir}" ;;
169                 *)  PKGSRCDIR="$( cd "${dir}" >/dev/null 2>&1 && pwd )" ;;
170                 esac
171                 break
172             fi
173         done
174     fi
175
176     if [ -z "$opt_g" ]; then
177         # Now we have PKGSRCDIR, use it to determine PACKAGES, and PKGCHK_CONF
178         # as well as AWK, GREP, SED, PKGCHK_TAGS and PKGCHK_NOTAGS
179         #
180         if [ ! -d "$PKGSRCDIR" -a \( -z "$opt_b" -o -n "$opt_s" \) ] ; then
181             fatal "Unable to locate PKGSRCDIR (${PKGSRCDIR:-not set})"
182         fi
183         if [ -z "$opt_b" -o -n "$opt_s" -o -d $PKGSRCDIR/pkgtools/pkg_chk ] ;
184             then
185             cd $PKGSRCDIR/pkgtools/pkg_chk
186             extract_make_vars Makefile \
187                     AWK GREP GZCAT GZIP_CMD ID PACKAGES PKGCHK_CONF PKGCHK_NOTAGS \
188                     PKGCHK_TAGS PKGCHK_UPDATE_CONF PKG_ADD PKG_DBDIR \
189                     PKG_DELETE PKG_ADMIN PKG_INFO PKG_SUFX SED SORT SU_CMD TSORT
190             if [ -z "$PACKAGES" ];then
191                 PACKAGES=$PKGSRCDIR/packages
192             fi
193         elif [ $MAKECONF != /dev/null ] ; then
194             extract_make_vars $MAKECONF PACKAGES PKGCHK_CONF \
195                         PKGCHK_UPDATE_CONF PKGCHK_TAGS PKGCHK_NOTAGS PKG_SUFX
196             if [ -z "$PACKAGES" ] ; then
197                 PACKAGES=`pwd`
198             fi
199         fi
200     fi
201
202     # .tgz/.tbz to regexp
203     PKG_SUFX_RE=`echo $PKG_SUFX | ${SED} 's/[.]/[.]/'`
204
205     if [ ! -d $PKG_DBDIR ] ; then
206         fatal "Unable to access PKG_DBDIR ($PKG_DBDIR)"
207     fi
208
209     if [ -z "$PKGCHK_CONF" ];then
210         PKGCHK_CONF=$PKGSRCDIR/pkgchk.conf
211     fi
212     if [ -z "$PKGCHK_UPDATE_CONF" ];then
213         PKGCHK_UPDATE_CONF=$PKGSRCDIR/pkgchk_update-$(hostname).conf
214     fi
215     }
216
217 fatal()
218     {
219     msg "*** $@" >&2
220     cleanup_and_exit 1
221     }
222
223 fatal_later()
224     {
225     msg "*** $@" >&2
226     fatal_later=1
227     }
228
229 fatal_later_check()
230     {
231     if [ "$fatal_later" = 1 ] ; then
232         cleanup_and_exit 1
233     fi
234     }
235
236 fatal_maybe()
237     {
238     if [ -z "$opt_k" ];then
239         fatal "$@"
240     else
241         msg "$@"
242     fi
243     }
244
245 generate_conf_from_installed()
246     {
247     FILE=$1
248     if [ -r $FILE ]; then
249         mv $FILE ${FILE}.old
250     fi
251     echo "# Generated automatically at $(date)" > $FILE
252     echo $(pkgdirs_from_installed) | tr ' ' '\n' >> $FILE
253     }
254
255 get_bin_pkg_info()
256     {
257     summary_file=$PACKAGES/$SUMMARY_FILE
258     if [ -f $summary_file ] ; then
259         if [ -z "$(find $PACKAGES -type f -newer $summary_file -name '*.t[bg]z')" ] ; then
260             msg_progress Reading $summary_file
261             ${GZCAT} $summary_file
262             return;
263         fi
264         echo "*** Ignoring $SUMMARY_FILE as PACKAGES contains newer files" >&2
265     fi
266     msg_progress Scan $PACKAGES
267     list_bin_pkgs | ${XARGS} ${PKG_INFO} -X
268     }
269
270 get_build_ver()
271     {
272     if [ -n "$opt_b" -a -z "$opt_s" ] ; then
273         ${PKG_INFO} -q -b $PACKAGES/$PKGNAME$PKG_SUFX | ${GREP} .
274         return
275     fi
276     # Unfortunately pkgsrc always outputs to a file, but it does
277     # helpfully allows us to specify the name
278     rm -f $MY_TMPFILE
279     ${MAKE} _BUILD_VERSION_FILE=$MY_TMPFILE $MY_TMPFILE
280     cat $MY_TMPFILE
281     }
282
283 list_bin_pkgs ()
284     {
285     ls -t $PACKAGES | grep "$PKG_SUFX_RE"'$' | ${SED} "s|^|$PACKAGES/|"
286     }
287
288 # Given a binary package filename as the first argumennt, return a list
289 # of exact package versions against which it was built and on which it
290 # depends
291 #
292 list_dependencies()
293     {
294     ${PKG_INFO} -q -n $1 | ${GREP} .. || true
295     }
296
297 # Pass a list of pkgdirs, outputs a tsorted list including any dependencies
298 #
299 list_packages()
300     {
301     # Convert passed in list of pkgdirs to a list of binary package files
302     pkglist=''
303     for pkgdir in $* ; do
304         pkgname=`pkgdir2pkgname $pkgdir`
305         if [ -z "$pkgname" ]; then
306             fatal_later "$pkgdir - Unable to extract pkgname"
307             continue
308         fi
309         if is_binary_available $pkgname ; then
310             pkglist="$pkglist $pkgname$PKG_SUFX"
311         else
312             fatal_later "$pkgname - no binary package found"
313         fi
314     done
315
316     # Variables used in this loop:
317     # pkglist: Current list of binary package files to check for dependencies
318     # next_pkglist: List of binary package files to check after pkglist
319     # pairlist: completed list of package + dependency for use in tsort
320     while [ -n "$pkglist" ] ; do
321         verbose "pkglist: $pkglist"
322         for pkg in $pkglist ; do
323             set -o noglob
324             deplist="$(list_dependencies $PACKAGES/$pkg)"
325             verbose "$pkg: dependencies - `echo $deplist`"
326             if [ -n "$deplist" ] ; then
327                 for depmatch in $deplist ; do
328                     dep=`${PKG_ADMIN} -b -d $PACKAGES lsbest "$depmatch"`
329                     if [ -z "$dep" ] ; then
330                         fatal_later "$depmatch: dependency missing for $pkg"
331                     else
332                         pairlist="$pairlist$dep $pkg\n"
333                         case $dep_cache in
334                             *" $dep "*)
335                                 # depmatch_cache is a quick cache of already
336                                 verbose "$pkg: $deplist - cached"
337                                 ;;
338                             *)
339                                 next_pkglist="$next_pkglist $dep"
340                                 dep_cache="$dep_cache $dep "
341                                 ;;
342                         esac
343                     fi
344                 done
345             else
346                 pairlist="$pairlist$pkg $pkg\n"
347             fi
348             set +o noglob
349         done
350         pkglist="$next_pkglist"
351         next_pkglist=
352     done
353     if [ -z "$opt_k" ] ; then
354         fatal_later_check
355     fi
356     printf "$pairlist" | ${TSORT}
357     }
358
359 pkgdir2pkgname()
360     {
361     pkgdir=$1
362     for pkgline in $PKGDB ; do
363         case $pkgline in
364             "$pkgdir:"*)
365                 echo $pkgline | ${SED} 's/[^:]*://'
366                 return;
367             ;;
368         esac
369     done
370     }
371
372 pkgdirs_from_conf()
373     {
374     CONF=$1; shift
375     LIST="$*"
376     if [ ! -r $CONF ];then
377         fatal "Unable to read PKGCHK_CONF '$CONF'"
378     fi
379
380     # Determine list of tags
381     #
382     if [ "$PKGSRCDIR" = NONE ]; then
383         OPSYS=$(uname -s)
384         OS_VERSION=$(uname -r)
385         MACHINE_ARCH=$(uname -p)
386     else
387         extract_make_vars Makefile OPSYS OS_VERSION MACHINE_ARCH
388     fi
389
390     TAGS="$(hostname | ${SED} -e 's,\..*,,'),$(hostname),$OPSYS-$OS_VERSION-$MACHINE_ARCH,$OPSYS-$OS_VERSION,$OPSYS-$MACHINE_ARCH,$OPSYS,$OS_VERSION,$MACHINE_ARCH"
391     if [ -f /usr/X11R6/lib/libX11.so -o -f /usr/X11R6/lib/libX11.a ];then
392         TAGS="$TAGS,x11"
393     fi
394     if [ -n "$PKGCHK_TAGS" ];then
395         TAGS="$TAGS,$PKGCHK_TAGS"
396     fi
397     if [ -n "$PKGCHK_NOTAGS" ];then
398         if [ -n "$opt_U" ];then
399                 opt_U="$opt_U,$PKGCHK_NOTAGS"
400         else
401                 opt_U="$PKGCHK_NOTAGS"
402         fi
403     fi
404
405     # If '-U' contains a '*' then we need to unset TAGS and PKGCHK_TAGS, but
406     # still pick up -D, and even package specific -U options
407     verbose "unset TAGS=$opt_U"
408     case ",$opt_U," in
409         *,\*,*)
410             TAGS=''
411             ;;
412     esac
413     if [ -n "$TAGS" ];then
414         if [ -n "$opt_D" ];then
415                 opt_D="$opt_D,$TAGS"
416         else
417                 opt_D="$TAGS"
418         fi
419     fi
420     verbose "set   TAGS=$opt_D"
421
422     # Extract list of valid pkgdirs (skip any 'alreadyset' in $LIST)
423     #
424     LIST="$LIST "$(${AWK} -v alreadyset="$LIST" -v setlist="$opt_D" -v unsetlist="$opt_U" '
425     BEGIN {
426         split(alreadyset, tmp, " ");
427         for (tag in tmp) { skip[tmp[tag]] = 1; }
428
429         split(setlist, tmp, ",");
430         for (tag in tmp) { taglist[tmp[tag]] = 1; }
431
432         split(unsetlist, tmp, ",");
433         for (tag in tmp) { skip[tmp[tag]] = 1; nofile[tmp[tag]] = 1 ;
434                         delete taglist[tmp[tag]] }
435
436         taglist["*"] = "*"
437     }
438     function and_expr_with_dict(expr, dict, ary, i, r, d) {
439         split(expr,ary,/\+/);
440         r = 1;
441         for (i in ary) {
442                 if (ary[i] ~ /^\// && ! nofile[ary[i]]) {
443                         if (getline d < ary[i] == -1)
444                             { r = 0; break ;}
445                 }
446                 else if (! (ary[i] in dict))
447                         { r = 0; break ;}
448         }
449         return r;
450     }
451     {
452     sub("#.*", "");
453     if (skip[$1])
454         next;
455     need = 0;
456     if ($0 ~ /\=/) {
457         split($0, tmp, "[ \t]*=");
458         taggroup = tmp[1];
459         sub("[ \t]*=", "=");
460         }
461     else
462         {
463         taggroup = ""
464         if (NF == 1)                    # If only one arg, we want pkg
465             need = 1;
466         }
467     for (f = 2 ; f<=NF ; ++f) {         # For each word on the line
468         if (sub("^-", "", $f)) {        # If it begins with a '-'
469                 if (f == 2)             # If first entry '-', assume '*'
470                     { need = 1; }
471                 if (and_expr_with_dict($f, taglist))
472                         next;           # If it is true, discard
473         } else {
474                 if (and_expr_with_dict($f, taglist))
475                         need = 1;       # If it is true, note needed
476         }
477     }
478     if (need)
479         if (taggroup)
480             taglist[taggroup] = 1
481         else
482             print $1;
483     }
484     ' < $CONF
485     )
486     echo $LIST
487     }
488
489 pkgdirs_from_installed()
490     {
491     ${PKG_INFO} -Bqa | ${AWK} -F= '/^PKGPATH=/{print $2}' | ${SORT}
492     }
493
494 msg()
495     {
496     if [ -n "$opt_L" ] ; then
497         echo "$@" >> "$opt_L"
498     fi
499     if [ -n "$opt_l" ] ; then
500         echo "$@" >&2
501     else
502         echo "$@"
503     fi
504     }
505
506 msg_progress()
507     {
508     if [ -z "$opt_q" ] ; then
509         msg "[ $@ ]"
510     fi
511     }
512
513 msg_n()
514     {
515     msg $ac_n "$*"$ac_c
516     }
517
518 pkg_fetch()
519     {
520     PKGNAME=$1
521     PKGDIR=$2
522
523     run_cmd "cd $PKGSRCDIR/$PKGDIR && ${MAKE} fetch-list | sh"
524     if [ -n "$FAIL" ]; then
525         FAIL_DONE=$FAIL_DONE" "$PKGNAME
526     else
527         FETCH_DONE=$FETCH_DONE" "$PKGNAME
528     fi
529     }
530
531 pkg_fetchlist()
532     {
533     PKGLIST=$@
534     msg_progress Fetch
535     while [ $# != 0 ]; do
536         pkg_fetch $1 $2
537         shift ; shift;
538     done
539     }
540
541 pkg_install()
542     {
543     PKGNAME=$1
544     PKGDIR=$2
545     INSTALL=$3
546
547     FAIL=
548     if [ -d $PKG_DBDIR/$PKGNAME ];then
549         msg "$PKGNAME installed in previous stage"
550         run_cmd_su "${PKG_ADMIN} unset automatic $PKGNAME"
551     elif [ -n "$opt_b" ] && is_binary_available $PKGNAME; then
552         if [ -n "$saved_PKG_PATH" ] ; then
553             export PKG_PATH=$saved_PKG_PATH
554         fi
555         run_cmd_su "${PKG_ADD} $PACKAGES/$PKGNAME$PKG_SUFX"
556         if [ -n "$saved_PKG_PATH" ] ; then
557             unset PKG_PATH
558         fi
559     elif [ -n "$opt_s" ]; then
560         run_cmd "cd $PKGSRCDIR/$PKGDIR && ${MAKE} update CLEANDEPENDS=yes"
561     fi
562
563     if [ -z "$opt_n" -a -z "$opt_q" -a ! -d $PKG_DBDIR/$PKGNAME ];then
564         FAIL=1
565     fi
566
567     if [ -n "$FAIL" ]; then
568         FAIL_DONE=$FAIL_DONE" "$PKGNAME
569     else
570         INSTALL_DONE=$INSTALL_DONE" "$PKGNAME
571     fi
572     }
573
574 pkg_installlist()
575     {
576     INSTALL=$1 ; shift
577     msg_progress $INSTALL
578     while [ $# != 0 ]; do
579         pkg_install $1 $2 $INSTALL
580         shift ; shift;
581     done
582     }
583
584 run_cmd()
585     {
586     FAIL=
587     if [ -n "$2" ]; then
588         FAILOK=$2
589     else
590         FAILOK=$opt_k
591     fi
592     if [ -z "$opt_q" ];then
593         msg $(date +%R) $1
594     fi
595     if [ -z "$opt_n" -a -z "$opt_q" ];then
596         if [ -n "$opt_L" ] ; then
597             sh -c "$1" >> "$opt_L" 2>&1 || FAIL=1
598         else
599             sh -c "$1" || FAIL=1
600         fi
601         if [ -n "$FAIL" ] ; then
602             msg "** '$1' failed"
603             if [ -n "$opt_L" ] ; then
604                 tail -100 "$opt_L" | egrep -v '^(\*\*\* Error code 1|Stop\.)' |\
605                         tail -40
606             fi
607             if [ "$FAILOK" != 1 ]; then
608                 fatal "** '$1' failed"
609             fi
610         fi
611     fi
612     }
613
614 run_cmd_su()
615     {
616     if [ -n "$SU_CMD" ]; then
617         run_cmd "${SU_CMD} '$1'" "$2"
618     else
619         run_cmd "$1" "$2"
620     fi
621     }
622
623 set_path()
624     {
625     arg=$1
626     case $arg in
627         http://*|ftp://*|/*)
628                 echo $arg ;;
629         *)      echo $basedir/$arg ;;
630     esac
631     }
632
633 usage()
634     {
635     if [ -n "$1" ] ; then
636         echo "$@"
637         echo
638     fi
639     echo 'Usage: pkg_chk [opts]
640         -a      Add all missing packages
641         -B      Check the "Build version" of packages
642         -b      Use binary packages
643         -C conf Use pkgchk.conf file 'conf'
644         -D tags Comma separated list of additional pkgchk.conf tags to set
645         -f      Perform a 'make fetch' for all required packages
646         -g      Generate an initial pkgchk.conf file
647         -h      This help
648         -k      Continue with further packages if errors are encountered
649         -L file Redirect output from commands run into file (should be fullpath)
650         -l      List binary packages including dependencies
651         -N      List installed packages for which a newer version is in TODO
652         -n      Display actions that would be taken, but do not perform them
653         -p      Display the list of pkgdirs that match the current tags
654         -P dir  Set PACKAGES dir (overrides any other setting)
655         -q      Do not display actions or take any action; only list packages
656         -r      Recursively remove mismatches (use with care)
657         -s      Use source for building packages
658         -U tags Comma separated list of pkgchk.conf tags to unset ('*' for all)
659         -u      Update all mismatched packages
660         -v      Verbose
661
662 pkg_chk verifies installed packages against pkgsrc.
663 The most common usage is 'pkg_chk -u -q' to check all installed packages or
664 'pkg_chk -u' to update all out of date packages.
665 For more advanced usage, including defining a set of desired packages based
666 on hostname and type, see pkg_chk(8).
667
668 If neither -b nor -s is given, both are assumed with -b preferred.
669 '
670     exit 1
671     }
672
673 verbose()
674     {
675     if [ -n "$opt_v" ] ; then
676         msg "$@" >&2
677     fi
678     }
679
680 verbose_var()
681     {
682     if [ -n "$opt_v" ] ; then
683         var=$1
684         shift
685         verbose Variable $var = $(eval echo \$$var) $@
686     fi
687     }
688
689 args=$(getopt BC:D:L:P:U:abcfghiklNnpqrsuv "$@")
690 if [ $? != 0 ]; then
691     opt_h=1
692 fi
693 set -o noglob # -U can be '*'
694 set -- $args
695 set +o noglob
696 while [ $# != 0 ]; do
697     case "$1" in
698         -a )    opt_a=1 ;;
699         -B )    opt_B=1 ;;
700         -b )    opt_b=1 ;;
701         -C )    opt_C="$2" ; shift ;;
702         -c )    opt_a=1 ; opt_q=1 ; echo "-c is deprecated - use -a -q" ;;
703         -D )    opt_D="$2" ; shift ;;
704         -f )    opt_f=1 ;;
705         -g )    opt_g=1 ;;
706         -h )    opt_h=1 ;;
707         -i )    opt_u=1 ; opt_q=1 ; echo "-i is deprecated - use -u -q" ;;
708         -k )    opt_k=1 ;;
709         -L )    opt_L="$2" ; shift ;;
710         -l )    opt_l=1 ;;
711         -N )    opt_N=1 ;;
712         -n )    opt_n=1 ;;
713         -p )    opt_p=1 ;;
714         -P )    opt_P="$2" ; shift ;;
715         -q )    opt_q=1 ;;
716         -r )    opt_r=1 ;;
717         -s )    opt_s=1 ;;
718         -U )    opt_U="$2" ; shift ;;
719         -u )    opt_u=1 ;;
720         -v )    opt_v=1 ;;
721         -- )    shift; break ;;
722     esac
723     shift
724 done
725
726 if [ -z "$opt_b" -a -z "$opt_s" ];then
727     opt_b=1; opt_s=1;
728 fi
729
730 if [ -z "$opt_a$opt_g$opt_l$opt_p$opt_r$opt_u$opt_N" ];
731 then
732     usage "Must specify at least one of -a, -g, -l, -p, -r, -u or -N";
733 fi
734
735 if [ -n "$opt_h" ];then
736     usage
737 fi
738
739 if [ $# != 0 ];then
740     usage "Additional argument ($*) given"
741 fi
742
743 # Hide PKG_PATH to avoid breakage in 'make' calls
744 saved_PKG_PATH=$PKG_PATH
745 unset PKG_PATH || true
746
747 test -n "$AWK"        || AWK="@AWK@"
748 test -n "$GREP"       || GREP="@GREP@"
749 test -n "$GZCAT"      || GZCAT="@GZCAT@"
750 test -n "$GZIP_CMD"   || GZIP_CMD="@GZIP_CMD@"
751 export GZIP_CMD
752 test -n "$ID"         || ID="@ID@"
753 test -n "$MAKE"       || MAKE="@MAKE@"
754 test -n "$MAKECONF"   || MAKECONF="@MAKECONF@"
755 test -n "$MKTEMP"     || MKTEMP="@MKTEMP@"
756 test -n "$PKG_ADD"    || PKG_ADD="@PKG_ADD@"
757 test -n "$PKG_ADMIN"  || PKG_ADMIN="@PKG_ADMIN@"
758 test -n "$PKG_DBDIR"  || PKG_DBDIR="@PKG_DBDIR@"
759 test -n "$PKG_DELETE" || PKG_DELETE="@PKG_DELETE@"
760 test -n "$PKG_INFO"   || PKG_INFO="@PKG_INFO@"
761 test -n "$SED"        || SED="@SED@"
762 test -n "$SORT"       || SORT="@SORT@"
763 test -n "$TSORT"      || TSORT="@TSORT@"
764 test -n "$XARGS"      || XARGS="@XARGS@"
765
766 MY_TMPDIR=`${MKTEMP} -d ${TMPDIR-/tmp}/${0##*/}.XXXXXX`
767 test -n "$MY_TMPDIR" || fatal "Couldn't create temporary directory."
768 MY_TMPFILE=$MY_TMPDIR/tmp
769
770 if [ -z "$MAKECONF" ] ; then
771     for mkconf in "@MAKECONF@" "@PREFIX@/etc/mk.conf" /etc/mk.conf ; do
772         if [ -f "$mkconf" ] ; then
773             MAKECONF="$mkconf"
774             break
775         fi
776     done
777 fi
778 if [ -z "$MAKECONF" -o ! -f "$MAKECONF" ] ; then
779     MAKECONF=/dev/null
780 fi
781 verbose_var MAKECONF
782
783 # grabbed from GNU configure
784 if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
785   # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
786   if (echo -n testing; echo 1,2,3) | ${SED} s/-n/xn/ | grep xn >/dev/null; then
787     ac_n= ac_c='
788 ' ac_t='        '
789   else
790     ac_n=-n ac_c= ac_t=
791   fi
792 else
793   ac_n= ac_c='\c' ac_t=
794 fi
795
796 if [ -n "$opt_L" ] ; then
797     printf '' > $opt_L
798 fi
799
800 basedir=$(pwd)
801 extract_variables
802 if [ -n "$opt_C" ] ; then
803     PKGCHK_CONF="$(set_path $opt_C)"
804 fi
805 if [ -n "$opt_P" ] ; then
806     PACKAGES="$(set_path $opt_P)"
807 fi
808 if [ -d $PACKAGES/All ] ; then
809     PACKAGES="$PACKAGES/All"
810 fi
811
812 if [ "`${ID} -u`" = 0 ] ; then
813     SU_CMD=
814 fi
815
816 if [ -n "$opt_N" ]; then
817         ${PKG_INFO} | \
818                 ${SED} -e "s/[  ].*//" -e "s/-[^-]*$//" \
819                        -e "s/py[0-9][0-9]pth-/py-/" \
820                        -e "s/py[0-9][0-9]-/py-/" | \
821                 while read a
822                 do
823                         b=$(grep "o $a-[0-9]" $PKGSRCDIR/doc/TODO | \
824                                 ${SED} -e "s/[  ]*o //")
825                 if [ "$b" ]
826                 then
827                         echo $a: $b
828                 fi
829         done
830 fi
831
832 AWK_PARSE_SUMMARY='$1=="PKGNAME"{pkgname=$2} $1=="PKGPATH"{pkgpath=$2} NF==0{if (pkgpath && pkgname) print pkgpath ":" pkgname; pkgpath=""; pkgname=""} END{if (pkgpath && pkgname) print pkgpath ":" pkgname}'
833
834 if [ -n "$opt_b" -a -z "$opt_s" ] ; then
835     case $PACKAGES in
836         http://*|ftp://*)
837             PKGDB=`ftp -o - $PACKAGES/$SUMMARY_FILE | ${GZIP_CMD} -cd \
838                 | ${AWK} -F= "$AWK_PARSE_SUMMARY"`
839             if [ -z "$PKGDB" ]
840             then
841                 PKGDB=`ftp -o - $PACKAGES/$OLD_SUMMARY_FILE`
842             fi;;
843         *)
844             if [ -d "$PACKAGES" ] ; then
845                 PKGDB=$(get_bin_pkg_info | bin_pkg_info2pkgdb)
846                 PKGSRCDIR=NONE
847             fi;;
848     esac
849 fi
850
851 if [ -n "$opt_g" ]; then
852     verbose "Write $PKGCHK_CONF based on installed packages"
853     generate_conf_from_installed $PKGCHK_CONF
854 fi
855
856 if [ -n "$opt_r" -o -n "$opt_u" ];then
857     verbose "Enumerate PKGDIRLIST from installed packages"
858     PKGDIRLIST=$(pkgdirs_from_installed)
859 fi
860
861 if [ -n "$opt_p" ] ; then
862     pkgdirs_from_conf $PKGCHK_CONF $PKGDIRLIST | tr ' ' '\n'
863     exit
864 fi
865
866 if [ -n "$opt_a" -o -n "$opt_l" ];then  # Append to PKGDIRLIST based on conf
867     verbose "Append to PKGDIRLIST based on config $PKGCHK_CONF"
868     PKGDIRLIST="$(pkgdirs_from_conf $PKGCHK_CONF $PKGDIRLIST)"
869 fi
870
871 if [ -n "$opt_l" ] ; then
872     list_packages $PKGDIRLIST
873 else
874     check_packages_installed $PKGDIRLIST
875 fi
876
877 if [ -n "$MISMATCH_TODO" ]; then
878     delete_and_recheck=1
879 elif [ -n "$opt_u" -a -f $PKGCHK_UPDATE_CONF ] ; then
880     delete_and_recheck=1
881 fi
882
883 if [ -n "$delete_and_recheck" ]; then
884     if [ -n "$opt_u" ] ; then            # Save current installed list
885         if [ -f $PKGCHK_UPDATE_CONF ] ; then
886             msg "Merging in previous $PKGCHK_UPDATE_CONF"
887             if [ -z "$opt_n" -a -z "$opt_q" ] ; then
888                 tmp=$(cat $PKGCHK_UPDATE_CONF)
889                 echo $tmp $(pkgdirs_from_installed) | tr ' ' '\n' | ${SORT} -u \
890                                                         > $PKGCHK_UPDATE_CONF
891                 tmp=
892             fi
893         else
894             if [ -z "$opt_n" -a -z "$opt_q" ] ; then
895                 echo $(pkgdirs_from_installed) | tr ' ' '\n' \
896                                                         > $PKGCHK_UPDATE_CONF
897             fi
898         fi
899     fi
900     if [ -n "$opt_r" -o -n "$opt_u" ] ; then
901         if [ -n "$MISMATCH_TODO" ]; then
902             delete_pkgs $MISMATCH_TODO
903             msg_progress Rechecking packages after deletions
904         fi
905         if [ -n "$opt_u" ]; then
906             PKGDIRLIST="$(pkgdirs_from_conf $PKGCHK_UPDATE_CONF $PKGDIRLIST)"
907         fi
908         if [ -n "$opt_a" -o -n "$opt_u" ]; then
909             check_packages_installed $PKGDIRLIST # May need to add more
910         fi
911     fi
912 fi
913
914 if [ -n "$opt_f" ] ; then
915     pkg_fetchlist $MISSING_TODO
916 fi
917
918 if [ -n "$MISSING_TODO" ] ; then
919     if [ -n "$opt_a" -o -n "$opt_u" ] ; then
920         pkg_installlist Install $MISSING_TODO
921     fi
922 fi
923
924 if [ -n "$opt_u" -a -z "$FAIL_DONE" -a -f $PKGCHK_UPDATE_CONF ] ; then
925     run_cmd "rm -f $PKGCHK_UPDATE_CONF"
926 fi
927
928 [ -z "$MISS_DONE" ] ||          msg "Missing:$MISS_DONE"
929 [ -z "$INSTALL_DONE" ] ||       msg "Installed:$INSTALL_DONE"
930
931 if [ -n "$FAIL_DONE" ] ; then
932    msg "Failed:$FAIL_DONE"
933    cleanup_and_exit 1
934 fi
935
936 cleanup_and_exit