main.c revision 179433
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 179433 2008-05-30 14:26:09Z 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 strlcpy (curr->name, pname, strlen(pname)+1); 179 curr->next = head; 180 head = curr; 181 } 182 } 183 184 if(ferror(fd)) { 185 fprintf(stderr, "error reading input\n"); 186 exit(EX_IOERR); 187 } 188 189 (void)fclose(fd); 190 } 191 } 192 closedir(dir); 193 } 194 } 195 196 /* Open UPDATING file */ 197 fd = fopen(updatingfile, "r"); 198 if(fd == NULL) { 199 fprintf(stderr, "can't open %s: %s\n", 200 updatingfile, strerror(errno)); 201 exit(EX_UNAVAILABLE); 202 } 203 204 /* Parse opened UPDATING file. */ 205 while(fgets(updatingline, maxcharperline, fd) != NULL) { 206 /* No entry is found so far */ 207 if (found == 0) { 208 /* Search for AFFECTS line to parse the portname. */ 209 tmpline1 = strstr(updatingline, affects); 210 211 if( tmpline1 != NULL ) { 212 curr = head; 213 while(curr != NULL) { 214 tmpline2 = strstr(updatingline, curr->name); 215 if( tmpline2 != NULL ) 216 break; 217 curr = curr->next; 218 } 219 if( tmpline2 != NULL ) { 220 /* If -d is set, check if entry is newer than the date. */ 221 if ( (dflag == 1) && (strncmp(dateline, date, 8) < 0)) 222 continue; 223 printf("%s", dateline); 224 printf("%s", updatingline); 225 found = 1; 226 } 227 } 228 } 229 /* Search for the end of an entry, if not found print the line. */ 230 else { 231 tmpline1 = strstr(updatingline, end); 232 if( tmpline1 == NULL ) 233 printf("%s", updatingline); 234 else { 235 linelength = strlen(updatingline); 236 if (linelength == 10) 237 found = 0; 238 else 239 printf("%s", updatingline); 240 } 241 } 242 /* Save the actual line, it could be a date. */ 243 dateline = strdup(updatingline); 244 } 245 246 if(ferror(fd)) { 247 fprintf(stderr, "error reading input\n"); 248 exit(EX_IOERR); 249 } 250 (void)fclose(fd); 251 252 exit(EX_OK); 253} 254 255int 256usage(void) 257{ 258 fprintf(stderr, 259 "usage: pkg_updating [-h] [-d YYYYMMDD] [-f file] [portname ...]\n"); 260 exit(EX_USAGE); 261} 262 263void 264cleanup(int sig) 265{ 266 if (sig) 267 exit(1); 268} 269