Introduce pkg_updating(1) which scans for installed ports and shows

all ports/UPDATING entries that affect one of the installed ports,
and are relevant on the given machine.

PR:		bin/117564
Submitted by:	Beat Gaetzi <beat@chruetertee.ch>
MFC after:	14 days
This commit is contained in:
Kirill Ponomarev 2007-11-02 22:46:30 +00:00
parent 8003dd03de
commit cc8b585463
5 changed files with 385 additions and 1 deletions

View File

@ -2,7 +2,7 @@
.include <bsd.own.mk>
SUBDIR= lib add create delete info ${_sign} version
SUBDIR= lib add create delete info ${_sign} updating version
.if ${MK_OPENSSL} != "no"
_sign= sign

View File

@ -0,0 +1,11 @@
# $FreeBSD$
PROG= pkg_updating
SRCS= main.c
CFLAGS+= -I${.CURDIR}/../lib
WARNS?= 6
WFORMAT?= 1
.include <bsd.prog.mk>

View File

@ -0,0 +1,257 @@
/*-
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <beat@chruetertee.ch> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Beat Gätzi
* ----------------------------------------------------------------------------
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/stat.h>
#include <sys/param.h> /* For MAXPATHLEN */
#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#include "pathnames.h"
typedef struct installedport {
struct installedport *next; /* List of installed ports. */
char name[LINE_MAX]; /* Name of the installed port. */
} INSTALLEDPORT;
int usage(void);
/*
* Parse /usr/port/UPDATING for corresponding entries. If no argument is
* passed to pkg_updating all entries for all installed ports are displayed.
* If a list of portnames is passed to pkg_updating only entries for the
* given portnames are displayed. Use the -d option to define that only newer
* entries as this date are shown.
*/
int
main(int argc, char *argv[])
{
/* Keyword for searching portname in UPDATING. */
const char *affects = "AFFECTS";
/* Indicate a date -> end of a entry. Will fail on 2100-01-01... */
const char *end = "20";
/* Keyword for searching origin portname of installed port. */
const char *origin = "@comment ORIGIN:";
const char *pkgdbpath = LOG_DIR; /* Location of pkgdb */
const char *updatingfile = UPDATING; /* Location of UPDATING */
char *date = NULL; /* Passed -d argument */
char *dateline = NULL; /* Saved date of an entry */
/* Tmp lines for parsing file */
char *tmpline1 = NULL;
char *tmpline2 = NULL;
char originline[LINE_MAX]; /* Line of +CONTENTS */
/* Temporary variable to create path to +CONTENTS for installed ports. */
char tmp_file[MAXPATHLEN];
char updatingline[LINE_MAX]; /* Line of UPDATING */
int ch; /* Char used by getopt */
int found = 0; /* Found an entry */
int linelength; /* Length of parsed line */
int maxcharperline = LINE_MAX; /* Max chars per line */
int dflag = 0; /* -d option set */
/* If pflag = 0 UPDATING will be checked for all installed ports. */
int pflag = 0;
size_t n; /* Offset to create path */
struct dirent *pkgdbdir; /* pkgdb directory */
struct stat attribute; /* attribute of pkgdb element */
/* Needed nodes for linked list with installed ports. */
INSTALLEDPORT *head = (INSTALLEDPORT *) NULL;
INSTALLEDPORT *curr = (INSTALLEDPORT *) NULL;
DIR *dir;
FILE *fd;
while ((ch = getopt(argc, argv, "f:p:d:")) != -1) {
switch (ch) {
case 'd':
dflag = 1;
date = optarg;
break;
case 'f':
updatingfile = optarg;
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
/* Check if passed date has a correct format. */
if (dflag == 1) {
linelength = strlen(date);
if (linelength != 8)
exit(EX_DATAERR);
if (strspn(date, "0123456789") != 8) {
fprintf(stderr, "unknown date format: %s\n", date);
exit(EX_DATAERR);
}
}
/* Save the list of passed portnames. */
if (argc != 0) {
pflag = 1;
while (*argv) {
if((curr = (INSTALLEDPORT *)
malloc(sizeof(INSTALLEDPORT))) == NULL)
(void)exit(EXIT_FAILURE);
strlcpy (curr->name, *argv, strlen(*argv) + 1);
curr->next = head;
head = curr;
(void)*argv++;
}
}
/*
* UPDATING will be parsed for all installed ports
* if no portname is passed.
*/
if (pflag == 0) {
/* Open /var/db/pkg and search for all installed ports. */
if((dir = opendir(pkgdbpath)) != NULL) {
while ((pkgdbdir = readdir(dir)) != NULL) {
if (strcmp(pkgdbdir->d_name, ".") != 0 &&
strcmp(pkgdbdir->d_name, "..") !=0) {
/* Create path to +CONTENTS file for each installed port */
n = strlcpy(tmp_file, pkgdbpath, strlen(pkgdbpath)+1);
n = strlcpy(tmp_file + n, "/", sizeof(tmp_file) - n);
n = strlcat(tmp_file + n, pkgdbdir->d_name,
sizeof(tmp_file) - n);
if(stat(tmp_file, &attribute) == -1) {
fprintf(stderr, "can't open %s: %s\n",
tmp_file, strerror(errno));
return EXIT_FAILURE;
}
if(attribute.st_mode & S_IFREG)
continue;
(void)strlcat(tmp_file + n, "/+CONTENTS",
sizeof(tmp_file) - n);
/* Open +CONTENT file */
fd = fopen(tmp_file, "r");
if(fd == NULL) {
fprintf(stderr, "warning: can't open %s: %s\n",
tmp_file, strerror(errno));
continue;
}
/*
* Parses +CONTENT for ORIGIN line and
* put element into linked list.
*/
while(fgets(originline, maxcharperline, fd) != NULL) {
tmpline1 = strstr(originline, origin);
if( tmpline1 != NULL ) {
/* Tmp variable to store port name. */
char *pname;
pname = strrchr(originline, (int)':');
pname++;
if((curr = (INSTALLEDPORT *)
malloc(sizeof(INSTALLEDPORT))) == NULL)
(void)exit(EXIT_FAILURE);
strlcpy (curr->name, pname, strlen(pname)+1);
curr->next = head;
head = curr;
}
}
if(ferror(fd)) {
fprintf(stderr, "error reading input\n");
exit(EX_IOERR);
}
(void)fclose(fd);
}
}
closedir(dir);
}
}
/* Open UPDATING file */
fd = fopen(updatingfile, "r");
if(fd == NULL) {
fprintf(stderr, "can't open %s: %s\n",
updatingfile, strerror(errno));
exit(EX_UNAVAILABLE);
}
/* Parse opened UPDATING file. */
while(fgets(updatingline, maxcharperline, fd) != NULL) {
/* No entry is found so far */
if (found == 0) {
/* Search for AFFECTS line to parse the portname. */
tmpline1 = strstr(updatingline, affects);
if( tmpline1 != NULL ) {
curr = head;
while(curr != NULL) {
tmpline2 = strstr(updatingline, curr->name);
if( tmpline2 != NULL )
break;
curr = curr->next;
}
if( tmpline2 != NULL ) {
/* If -d is set, check if entry is newer than the date. */
if ( (dflag == 1) && (strncmp(dateline, date, 8) < 0))
continue;
printf("%s", dateline);
printf("%s", updatingline);
found = 1;
}
}
}
/* Search for the end of an entry, if not found print the line. */
else {
tmpline1 = strstr(updatingline, end);
if( tmpline1 == NULL )
printf("%s", updatingline);
else {
linelength = strlen(updatingline);
if (linelength == 10)
found = 0;
else
printf("%s", updatingline);
}
}
/* Save the actual line, it could be a date. */
dateline = strdup(updatingline);
}
if(ferror(fd)) {
fprintf(stderr, "error reading input\n");
exit(EX_IOERR);
}
(void)fclose(fd);
exit(EX_OK);
}
int
usage(void)
{
fprintf(stderr,
"usage: pkg_updating [-d YYYYMMDD] [-f file] [portname ...]\n");
exit(EX_USAGE);
}

View File

@ -0,0 +1,28 @@
/*-
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <beat@chruetertee.ch> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Beat Gätzi
* ----------------------------------------------------------------------------
*
* $FreeBSD$
*
*/
/* Copy from ../version/version.h */
/* Where the ports lives by default */
#define DEF_PORTS_DIR "/usr/ports/UPDATING"
/* just in case we change the environment variable name */
#define PORTSDIR "PORTSDIR"
/* macro to get name of directory where we put logging information */
#define UPDATING (getenv(PORTSDIR) ? strcat(getenv(PORTSDIR), \
"/UPDATING") : DEF_PORTS_DIR)
/* Where we put logging information by default, else ${PKG_DBDIR} if set */
#define DEF_LOG_DIR "/var/db/pkg"
/* just in case we change the environment variable name */
#define PKG_DBDIR "PKG_DBDIR"
/* macro to get name of directory where we put logging information */
#define LOG_DIR (getenv(PKG_DBDIR) ? getenv(PKG_DBDIR) : DEF_LOG_DIR)

View File

@ -0,0 +1,88 @@
.\"
.\" FreeBSD updating - Scan the installed ports and show all UPDATING entries
.\" that affect one of the installed ports. Alternative a list of portnames
.\" could be passed to pkg_updating
.\"
.\" "THE BEER-WARE LICENSE" (Revision 42):
.\" <beat@chruetertee.ch> wrote this file. As long as you retain this notice you
.\" can do whatever you want with this stuff. If we meet some day, and you think
.\" this stuff is worth it, you can buy me a beer in return. Beat Gätzi
.\"
.\" $FreeBSD$
.\"
.Dd November 2, 2007
.Dt PKG_UPDATING 1
.Os
.Sh NAME
.Nm pkg_updating
.Nd a utility for displaying UPDATING entries of software packages
.Sh SYNOPSIS
.Nm
.Op Fl d Ar date
.Op Fl f Ar file
.Op Ar pkg-name ...
.Nm
.Sh DESCRIPTION
The
.Nm
command scans the installed ports and show all UPDATING entries that affect one
of the installed ports. Alternative a list of pkg-names could be passed.
.Sh OPTIONS
The following command line options are supported:
.Bl -tag -width indent
.It Ar pkg-name ...
UPDATING entries for the named packages are displayed.
.It Fl d Ar date
Only entries newer than this date are shown. Use a YYYYMMDD date format.
.It Fl f Ar UPDATING file
Defines a alternative location of the UPDATING file.
.El
.Sh EXAMPLES
.Bl -tag -width indent
.Dl pkg_updating
.Pp
Shows all entries of all installed ports.
.Pp
.Dl pkg_updating -d 20070101
.Pp
Shows all entries of all installed ports since 2007-01-01.
.Pp
.Dl pkg_updating apache mysql
.Pp
Shows all entries for all apache and mysql ports.
.Pp
.Dl pkg_updating -d 20060101 apache
.Pp
Shows all apache entries since 2006-01-01.
.Pp
.Dl pkg_updating -f /tmp/UPDATING
.Pp
Defines that the UPDATING file is in /tmp and shows all entries of all
installed ports
.Pp
.El
.Sh ENVIRONMENT
.Bl -tag -width PKG_DBDIR
.It Ev PKG_DBDIR
Specifies an alternative location for the installed package database.
.It Ev PORTSDIR
Location of the ports tree.
.El
.Sh FILES
.Bl -tag -width /var/db/pkg -compact
.It Pa /var/db/pkg
Default location of the installed package database.
.It Pa /usr/ports
The default ports directory and default location of the UPDATING file
.El
.Sh SEE ALSO
.Xr pkg_add 1 ,
.Xr pkg_create 1 ,
.Xr pkg_delete 1 ,
.Xr pkg_version 1
.Sh AUTHORS
.An Beat Gätzi Aq beat@chruetertee.ch
.Sh CONTRIBUTORS
.An Martin Tournoij Aq carpetsmoker@xs4all.nl
.Sh BUGS
Sure to be some.