1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Copyright (c) 2018, Joyent, Inc.
  28  */
  29 
  30 #include <stdio.h>
  31 #include <fcntl.h>
  32 #include <strings.h>
  33 #include <ctype.h>
  34 #include <stdlib.h>
  35 
  36 #include "list.h"
  37 #include "proto_list.h"
  38 
  39 #define FS      " \t\n"
  40 
  41 static void
  42 error(const char *msg, int lc)
  43 {
  44         (void) fprintf(stderr, "warning: line %d - %s\n", lc, msg);
  45 }
  46 
  47 /*
  48  * int is_num()
  49  *
  50  * returns 1 if the string is entirely numeric - if not it returns 0
  51  *
  52  */
  53 static int
  54 is_num(const char *str)
  55 {
  56         int i;
  57         int len = strlen(str);
  58 
  59         if (len < 1)
  60                 return (0);
  61 
  62         for (i = 0; i < len; i++)
  63                 if (!isdigit(str[i]))
  64                         return (0);
  65         return (1);
  66 }
  67 
  68 /*
  69  * void check_line()
  70  *
  71  * try and do some sanity/syntax checking against the line just
  72  * read in - print warning messages as errors are encountered.
  73  *
  74  * these are simple checks, but then they catch the simple errors-:)
  75  *
  76  */
  77 static void
  78 check_line(char *v[], int lc)
  79 {
  80         if ((!v[NAME]) || ((int)strlen(v[NAME]) < 1))
  81                 error("bad name", lc);
  82 
  83         if ((!v[SRC]) || ((int)strlen(v[SRC])) < 1)
  84                 error("bad source/symbolic line", lc);
  85 
  86         if ((!v[PERM]) || ((int)strlen(v[PERM]) < 3) || (!is_num(v[PERM])))
  87                 error("bad permissions", lc);
  88 
  89         if ((!v[OWNR]) || ((int)strlen(v[OWNR]) < 2))
  90                 error("bad owner", lc);
  91 
  92         if ((!v[GRP]) || ((int)strlen(v[GRP]) < 2))
  93                 error("bad group", lc);
  94 
  95         if ((!v[INO]) || (!is_num(v[INO])))
  96                 error("bad i-node", lc);
  97 
  98         if ((!v[LCNT]) || (!is_num(v[LCNT])))
  99                 error("bad link-count", lc);
 100 
 101         if ((!v[CODE]) || ((*v[CODE] != 'f') && (*v[CODE] != 'c') &&
 102             (*v[CODE] != 'd') && (*v[CODE] != 'b') &&
 103             (*v[CODE] != 'v') && (*v[CODE] != 'e') &&
 104             (*v[CODE] != 's')) || ((int)strlen(v[CODE]) > 1))
 105                 error("bad type", lc);
 106 
 107         if ((!v[MAJOR]) || ((!is_num(v[MAJOR])) && (*v[MAJOR] != '-')))
 108                 error("bad major number", lc);
 109 
 110         if ((!v[MINOR]) || ((!is_num(v[MINOR])) && (*v[MINOR] != '-')))
 111                 error("bad minor number", lc);
 112 }
 113 
 114 static char **
 115 get_line(FILE *fp, char *v[])
 116 {
 117         char    *rc;
 118         char    *p;
 119         int     len;
 120         int     cont = 1;
 121         static char     buf[BUFSIZ];
 122         static int      line_count = 0;
 123 
 124         p = buf;
 125         p[0] = '\0';
 126 
 127         do {
 128                 rc = fgets(p, BUFSIZ, fp);
 129                 line_count ++;
 130                 /*
 131                  * check for continuation marks at the end of the
 132                  * line - if it exists then append the next line at the
 133                  * end of this one.
 134                  */
 135                 if (buf[0] == '#') {
 136                         /*
 137                          * skip comments.
 138                          */
 139                         continue;
 140                 } else if ((rc != NULL) && ((len = strlen(p)) > 1) &&
 141                     (p[len - 2] == '\\')) {
 142                         /*
 143                          * check for continuation marks at the end of the
 144                          * line - if it exists then append the next line at the
 145                          * end of this one.
 146                          */
 147                         p += len - 2;
 148                 } else
 149                         cont = 0;
 150         } while (cont);
 151 
 152         if (rc == NULL)
 153                 return (NULL);
 154 
 155         /*
 156          * breakup the line into the various fields.
 157          */
 158         v[PROTOS] = index(buf, ';');
 159         if (v[PROTOS])
 160                 *v[PROTOS]++ = '\0';
 161         v[0]  = strtok(buf, FS);
 162         for (cont = 1; cont < FIELDS - 1; cont++)
 163                 v[cont] = strtok(NULL, FS);
 164 
 165         check_line(v, line_count);
 166 
 167         return (v);
 168 }
 169 
 170 static void
 171 parse_line(char **v, elem *e)
 172 {
 173         e->flag = 0;
 174         e->pkgs = NULL;
 175         e->arch = P_ISA;
 176         (void) strcpy(e->name, v[NAME]);
 177         e->perm = strtol(v[PERM], NULL, 8);
 178         (void) strcpy(e->owner, v[OWNR]);
 179         (void) strcpy(e->group, v[GRP]);
 180         e->inode = atoi(v[INO]);
 181         e->ref_cnt = atoi(v[LCNT]);
 182         e->file_type = *v[CODE];
 183         if ((v[MAJOR][0] == '-') && (v[MAJOR][1] == '\0'))
 184                 e->major = -1;
 185         else
 186                 e->major = atoi(v[MAJOR]);
 187 
 188         if ((v[MINOR][0] == '-') && (v[MINOR][1] == '\0'))
 189                 e->minor = -1;
 190         else
 191                 e->minor = atoi(v[MINOR]);
 192 
 193         if ((v[SYM][0] == '-') && (v[SYM][1] == '\0'))
 194                 e->symsrc = NULL;
 195         else {
 196                 e->symsrc = malloc(strlen(v[SYM]) + 1);
 197                 (void) strcpy(e->symsrc, v[SYM]);
 198                 if (e->file_type != SYM_LINK_T)
 199 #if defined(__sparc)
 200                         if (strncmp(e->symsrc, "sun4/", 5) == 0)
 201                                 e->arch = P_SUN4;
 202                         else if (strncmp(e->symsrc, "sun4c/", 6) == 0)
 203                                 e->arch = P_SUN4c;
 204                         else if (strncmp(e->symsrc, "sun4u/", 6) == 0)
 205                                 e->arch = P_SUN4u;
 206                         else if (strncmp(e->symsrc, "sun4d/", 6) == 0)
 207                                 e->arch = P_SUN4d;
 208                         else if (strncmp(e->symsrc, "sun4e/", 6) == 0)
 209                                 e->arch = P_SUN4e;
 210                         else if (strncmp(e->symsrc, "sun4m/", 6) == 0)
 211                                 e->arch = P_SUN4m;
 212                         else if (strncmp(e->symsrc, "sun4v/", 6) == 0)
 213                                 e->arch = P_SUN4v;
 214 #elif defined(__i386)
 215                         if (strncmp(e->symsrc, "i86pc/", 6) == 0)
 216                                 e->arch = P_I86PC;
 217 #elif defined(__ppc)
 218                         if (strncmp(e->symsrc, "prep/", 5) == 0)
 219                                 e->arch = P_PREP;
 220 #else
 221 #error "Unknown instruction set"
 222 #endif
 223                         else {
 224                                 (void) fprintf(stderr,
 225                                     "warning: Unknown relocation architecture "
 226                                     "for %s\n", e->symsrc);
 227                         }
 228 
 229         }
 230 }
 231 
 232 int
 233 read_in_protolist(const char *pname, elem_list *list, int verbose)
 234 {
 235         FILE    *proto_fp;
 236         char    *line_vec[FIELDS];
 237         int     count = 0;
 238         static elem     *e = NULL;
 239 
 240         list->type = PROTOLIST_LIST;
 241 
 242         if ((proto_fp = fopen(pname, "r")) == NULL) {
 243                 perror(pname);
 244                 exit(1);
 245         }
 246 
 247         if (verbose)
 248                 (void) printf("reading in proto_list(%s)...\n", pname);
 249 
 250         count = 0;
 251         while (get_line(proto_fp, line_vec)) {
 252                 if (!e)
 253                         e = (elem *)calloc(1, sizeof (elem));
 254 
 255                 parse_line(line_vec, e);
 256                 if (!find_elem(list, e, FOLLOW_LINK)) {
 257                         add_elem(list, e);
 258                         e = NULL;
 259                         count++;
 260                 }
 261         }
 262 
 263         if (verbose)
 264                 (void) printf("read in %d lines\n", count);
 265 
 266         (void) fclose(proto_fp);
 267 
 268         return (count);
 269 }