Linux软件管理平台设计与实现
上QQ阅读APP看书,第一时间看更新

1.4 RPM解析例程

笔者基于rpm-devel开发了一个C程序,用来读取RPM文件的基本信息并打印到标准输出。如果你对前面章节介绍的知识已经理解并掌握了,下面这段代码就比较容易阅读了。

核心代码片段如下:

char * readHeaderString (Header header,int_32 tag_id)
    {
          int_32 type;
          void *pointer;
          int_32 data_size;
          //获取header中的一个string
          int header_status = headerGetEntry (header,
                tag_id,&type,&pointer,&data_size);
          if(header_status)
                {
                      if(type == RPM_STRING_TYPE)
                          {
                                  return pointer;
                          }
                }
          return NULL;
    }
int samplerpm (const char *szrpm)
    {
          char g_szname[1024] = {0};
          FD_t fd = Fopen (szrpm,"r");
          memset (g_szname,0,1024);
          sprintf (g_szname,"%s",szrpm);
          fflush (stdin);
          fflush (stdout);
          if(!fd)
                {
                       printf ("open file '%s' failed\n",szrpm);
                       return 0;
                }
          struct rpmlead plead;
          int lead = readLead (fd,&plead);//读取lead结构体
          if(lead)
                {
                       printf ("readLead of '%s' failed\n",szrpm);
                       Fclose (fd);
                       return 0;
          }
          Header header;
          //读取第一个header structure—signature
          rpmRC ret = rpmReadSignature (fd,&header,plead.signature_type);
          if(ret != RPMRC_OK)
                {
                       printf ("rpmReadSignature of '%s' failed\n",szrpm);
                       Fclose (fd);
                       return 0;
                }
          //读取第一个header structure—header
          Header newheader =
          headerRead (fd,(plead.major >= 3)? HEADER_MAGIC_YES :HEADER_MAGIC_NO);
          if(!newheader)
                {
                       printf ("headerRead of '%s' failed\n",szrpm);
                       Fclose (fd);
                       return 0;
                }
          //读取各个TAG
          const char *name = readHeaderString (newheader,RPMTAG_NAME);
          const char *version = readHeaderString (newheader,RPMTAG_VERSION);
          const char *release = readHeaderString (newheader,RPMTAG_RELEASE);
          const char *group = readHeaderString (newheader,RPMTAG_GROUP);
          const char *packager = readHeaderString (newheader,RPMTAG_PACKAGER);
          if (!group)group = "NONE_GROUP";
          if (!packager)packager = "NONE_PACKAGER";
          printf ("name:%s\nversion:%s\nrelease:%s\ngroup:%s\npackager:%s\n\n",
          name,version,release,group,packager);
          Fclose (fd);
          return 1;
    }

可执行程序的编译方法如下:

gcc test.c-I/usr/include/rpm-lrpm-lrpmdb-lrpmio-lpopt-o test_rpm

可以通过以下方法进行测试:

./test_rpm ./mysql-server-5.0.77-4.el5_6.6.x86_64.rpm

输出如下:

name:mysql-server
version:5.0.77
release:4.el5_6.6
group:Applications/Databases
packager:Red Hat,Inc.<http://bugzilla.redhat.com/bugzilla>

可以看到,test_rpm这个程序解析并打印了指定RPM文件的基本信息,读者可以参考文档对该程序进行功能细化。

由于笔者并没阅读rpm命令或者rpmbuild的源码,因此对RPM格式的剖析只能到此深度,不过rpmbuild的实现应该也是类似的,感兴趣的读者可以参考RPM的文档和源码进一步学习。