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