main.c revision 179760
1/*- 2 * ---------------------------------------------------------------------------- 3 * "THE BEER-WARE LICENSE" (Revision 42): 4 * <beat@chruetertee.ch> wrote this file. As long as you retain this notice you 5 * can do whatever you want with this stuff. If we meet some day, and you think 6 * this stuff is worth it, you can buy me a beer in return. Beat G�tzi 7 * ---------------------------------------------------------------------------- 8 */ 9 10#include <sys/cdefs.h> 11__FBSDID("$FreeBSD: head/usr.sbin/pkg_install/updating/main.c 179760 2008-06-12 15:21:13Z flz $"); 12 13#include <errno.h> 14#include <limits.h> 15#include <sysexits.h> 16#include <getopt.h> 17 18#include "lib.h" 19#include "pathnames.h" 20 21typedef struct installedport { 22 struct installedport *next; /* List of installed ports. */ 23 char name[LINE_MAX]; /* Name of the installed port. */ 24} INSTALLEDPORT; 25 26int usage(void); 27 28static char opts[] = "d:f:h"; 29static struct option longopts[] = { 30 { "date", required_argument, NULL, 'd' }, 31 { "file", required_argument, NULL, 'f' }, 32 { "help", no_argument, NULL, 'h' }, 33 { NULL, 0, NULL, 0 }, 34}; 35 36/* 37 * Parse /usr/port/UPDATING for corresponding entries. If no argument is 38 * passed to pkg_updating all entries for all installed ports are displayed. 39 * If a list of portnames is passed to pkg_updating only entries for the 40 * given portnames are displayed. Use the -d option to define that only newer 41 * entries as this date are shown. 42 */ 43int 44main(int argc, char *argv[]) 45{ 46 /* Keyword for searching portname in UPDATING. */ 47 const char *affects = "AFFECTS"; 48 /* Indicate a date -> end of a entry. Will fail on 2100-01-01... */ 49 const char *end = "20"; 50 /* Keyword for searching origin portname of installed port. */ 51 const char *origin = "@comment ORIGIN:"; 52 const char *pkgdbpath = LOG_DIR; /* Location of pkgdb */ 53 const char *updatingfile = UPDATING; /* Location of UPDATING */ 54 55 char *date = NULL; /* Passed -d argument */ 56 char *dateline = NULL; /* Saved date of an entry */ 57 /* Tmp lines for parsing file */ 58 char *tmpline1 = NULL; 59 char *tmpline2 = NULL; 60 61 char originline[LINE_MAX]; /* Line of +CONTENTS */ 62 /* Temporary variable to create path to +CONTENTS for installed ports. */ 63 char tmp_file[MAXPATHLEN]; 64 char updatingline[LINE_MAX]; /* Line of UPDATING */ 65 66 int ch; /* Char used by getopt */ 67 int found = 0; /* Found an entry */ 68 int linelength; /* Length of parsed line */ 69 int maxcharperline = LINE_MAX; /* Max chars per line */ 70 int dflag = 0; /* -d option set */ 71 /* If pflag = 0 UPDATING will be checked for all installed ports. */ 72 int pflag = 0; 73 74 size_t n; /* Offset to create path */ 75 76 struct dirent *pkgdbdir; /* pkgdb directory */ 77 struct stat attribute; /* attribute of pkgdb element */ 78 79 /* Needed nodes for linked list with installed ports. */ 80 INSTALLEDPORT *head = (INSTALLEDPORT *) NULL; 81 INSTALLEDPORT *curr = (INSTALLEDPORT *) NULL; 82 83 DIR *dir; 84 FILE *fd; 85 86 while ((ch = getopt_long(argc, argv, opts, longopts, NULL)) != -1) { 87 switch (ch) { 88 case 'd': 89 dflag = 1; 90 date = optarg; 91 break; 92 case 'f': 93 updatingfile = optarg; 94 break; 95 case 'h': 96 default: 97 usage(); 98 } 99 } 100 argc -= optind; 101 argv += optind; 102 103 /* Check if passed date has a correct format. */ 104 if (dflag == 1) { 105 linelength = strlen(date); 106 if (linelength != 8) 107 exit(EX_DATAERR); 108 if (strspn(date, "0123456789") != 8) { 109 fprintf(stderr, "unknown date format: %s\n", date); 110 exit(EX_DATAERR); 111 } 112 } 113 114 /* Save the list of passed portnames. */ 115 if (argc != 0) { 116 pflag = 1; 117 while (*argv) { 118 if((curr = (INSTALLEDPORT *) 119 malloc(sizeof(INSTALLEDPORT))) == NULL) 120 (void)exit(EXIT_FAILURE); 121 strlcpy (curr->name, *argv, strlen(*argv) + 1); 122 curr->next = head; 123 head = curr; 124 (void)*argv++; 125 } 126 } 127 128 /* 129 * UPDATING will be parsed for all installed ports 130 * if no portname is passed. 131 */ 132 if (pflag == 0) { 133 /* Open /var/db/pkg and search for all installed ports. */ 134 if((dir = opendir(pkgdbpath)) != NULL) { 135 while ((pkgdbdir = readdir(dir)) != NULL) { 136 if (strcmp(pkgdbdir->d_name, ".") != 0 && 137 strcmp(pkgdbdir->d_name, "..") !=0) { 138 139 /* Create path to +CONTENTS file for each installed port */ 140 n = strlcpy(tmp_file, pkgdbpath, strlen(pkgdbpath)+1); 141 n = strlcpy(tmp_file + n, "/", sizeof(tmp_file) - n); 142 n = strlcat(tmp_file + n, pkgdbdir->d_name, 143 sizeof(tmp_file) - n); 144 if(stat(tmp_file, &attribute) == -1) { 145 fprintf(stderr, "can't open %s: %s\n", 146 tmp_file, strerror(errno)); 147 return EXIT_FAILURE; 148 } 149 if(attribute.st_mode & S_IFREG) 150 continue; 151 (void)strlcat(tmp_file + n, "/", 152 sizeof(tmp_file) - n); 153 (void)strlcat(tmp_file + n, CONTENTS_FNAME, 154 sizeof(tmp_file) - n); 155 156 /* Open +CONTENT file */ 157 fd = fopen(tmp_file, "r"); 158 if(fd == NULL) { 159 fprintf(stderr, "warning: can't open %s: %s\n", 160 tmp_file, strerror(errno)); 161 continue; 162 } 163 164 /* 165 * Parses +CONTENT for ORIGIN line and 166 * put element into linked list. 167 */ 168 while(fgets(originline, maxcharperline, fd) != NULL) { 169 tmpline1 = strstr(originline, origin); 170 if( tmpline1 != NULL ) { 171 /* Tmp variable to store port name. */ 172 char *pname; 173 pname = strrchr(originline, (int)':'); 174 pname++; 175 if((curr = (INSTALLEDPORT *) 176 malloc(sizeof(INSTALLEDPORT))) == NULL) 177 (void)exit(EXIT_FAILURE); 178 if (pname[strlen(pname) - 1] == '\n') 179 pname[strlen(pname) - 1] = '\0'; 180 strlcpy (curr->name, pname, strlen(pname)+1); 181 curr->next = head; 182 head = curr; 183 } 184 } 185 186 if(ferror(fd)) { 187 fprintf(stderr, "error reading input\n"); 188 exit(EX_IOERR); 189 } 190 191 (void)fclose(fd); 192 } 193 } 194 closedir(dir); 195 } 196 } 197 198 /* Open UPDATING file */ 199 fd = fopen(updatingfile, "r"); 200 if(fd == NULL) { 201 fprintf(stderr, "can't open %s: %s\n", 202 updatingfile, strerror(errno)); 203 exit(EX_UNAVAILABLE); 204 } 205 206 /* Parse opened UPDATING file. */ 207 while(fgets(updatingline, maxcharperline, fd) != NULL) { 208 /* No entry is found so far */ 209 if (found == 0) { 210 /* Search for AFFECTS line to parse the portname. */ 211 tmpline1 = strstr(updatingline, affects); 212 213 if( tmpline1 != NULL ) { 214 curr = head; 215 while(curr != NULL) { 216 tmpline2 = strstr(updatingline, curr->name); 217 if( tmpline2 != NULL ) 218 break; 219 curr = curr->next; 220 } 221 if( tmpline2 != NULL ) { 222 /* If -d is set, check if entry is newer than the date. */ 223 if ( (dflag == 1) && (strncmp(dateline, date, 8) < 0)) 224 continue; 225 printf("%s", dateline); 226 printf("%s", updatingline); 227 found = 1; 228 } 229 } 230 } 231 /* Search for the end of an entry, if not found print the line. */ 232 else { 233 tmpline1 = strstr(updatingline, end); 234 if( tmpline1 == NULL ) 235 printf("%s", updatingline); 236 else { 237 linelength = strlen(updatingline); 238 if (linelength == 10) 239 found = 0; 240 else 241 printf("%s", updatingline); 242 } 243 } 244 /* Save the actual line, it could be a date. */ 245 dateline = strdup(updatingline); 246 } 247 248 if(ferror(fd)) { 249 fprintf(stderr, "error reading input\n"); 250 exit(EX_IOERR); 251 } 252 (void)fclose(fd); 253 254 exit(EX_OK); 255} 256 257int 258usage(void) 259{ 260 fprintf(stderr, 261 "usage: pkg_updating [-h] [-d YYYYMMDD] [-f file] [portname ...]\n"); 262 exit(EX_USAGE); 263} 264 265void 266cleanup(int sig) 267{ 268 if (sig) 269 exit(1); 270} 271