getservice.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * Copyright (C) 2010 Bernhard Reutner-Fischer <uclibc@uclibc.org>
  3. *
  4. * Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
  5. */
  6. /* /etc/services
  7. # service-name port/protocol [aliases ...]
  8. discard 9/udp sink null
  9. service-name: case sensitive friendly name of the service
  10. port: decimal port number
  11. protocol: protocols(5) compatible entry
  12. aliases: case sensitive optional space or tab separated list of other names
  13. */
  14. #include <features.h>
  15. #include <netdb.h>
  16. #include <string.h>
  17. #include <stdlib.h>
  18. #include <netinet/in.h>
  19. #include <arpa/inet.h>
  20. #include <errno.h>
  21. #include <unistd.h>
  22. #include "internal/parse_config.h"
  23. #include <bits/uClibc_mutex.h>
  24. __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
  25. #define MINTOKENS 3
  26. #define MAXALIASES 8 /* we seldomly need more than 1 alias */
  27. #define MAXTOKENS (MINTOKENS + MAXALIASES + 1)
  28. #define BUFSZ (255) /* one line */
  29. #define SBUFSIZE (BUFSZ + 1 + (sizeof(char *) * MAXTOKENS))
  30. static parser_t *servp = NULL;
  31. static struct servent serve;
  32. static char *servbuf = NULL;
  33. static size_t servbuf_sz = SBUFSIZE;
  34. static smallint serv_stayopen;
  35. void setservent(int stayopen)
  36. {
  37. __UCLIBC_MUTEX_LOCK(mylock);
  38. if (servp)
  39. config_close(servp);
  40. servp = config_open(_PATH_SERVICES);
  41. if (stayopen)
  42. serv_stayopen = 1;
  43. __UCLIBC_MUTEX_UNLOCK(mylock);
  44. }
  45. libc_hidden_def(setservent)
  46. void endservent(void)
  47. {
  48. __UCLIBC_MUTEX_LOCK(mylock);
  49. if (servp) {
  50. config_close(servp);
  51. servp = NULL;
  52. }
  53. serv_stayopen = 0;
  54. __UCLIBC_MUTEX_UNLOCK(mylock);
  55. }
  56. libc_hidden_def(endservent)
  57. int getservent_r(struct servent *result_buf,
  58. char *buf, size_t buflen, struct servent **result)
  59. {
  60. char **tok = NULL;
  61. const size_t aliaslen = sizeof(char *) * MAXTOKENS;
  62. int ret = ERANGE;
  63. *result = NULL;
  64. if (buflen < aliaslen
  65. || (buflen - aliaslen) < BUFSZ + 1)
  66. goto DONE_NOUNLOCK;
  67. __UCLIBC_MUTEX_LOCK(mylock);
  68. ret = ENOENT;
  69. if (servp == NULL)
  70. setservent(serv_stayopen);
  71. if (servp == NULL)
  72. goto DONE;
  73. servp->data = buf;
  74. servp->data_len = aliaslen;
  75. servp->line_len = buflen - aliaslen;
  76. /* <name>[[:space:]]<port>/<proto>[[:space:]][<aliases>] */
  77. if (!config_read(servp, &tok, MAXTOKENS - 1, MINTOKENS, "# \t/", PARSE_NORMAL)) {
  78. goto DONE;
  79. }
  80. result_buf->s_name = *(tok++);
  81. result_buf->s_port = htons((u_short) atoi(*(tok++)));
  82. result_buf->s_proto = *(tok++);
  83. result_buf->s_aliases = tok;
  84. *result = result_buf;
  85. ret = 0;
  86. DONE:
  87. __UCLIBC_MUTEX_UNLOCK(mylock);
  88. DONE_NOUNLOCK:
  89. errno = ret;
  90. return errno;
  91. }
  92. libc_hidden_def(getservent_r)
  93. static void __initbuf(void)
  94. {
  95. if (!servbuf)
  96. servbuf = malloc(SBUFSIZE);
  97. if (!servbuf)
  98. abort();
  99. }
  100. struct servent *getservent(void)
  101. {
  102. struct servent *result;
  103. __initbuf();
  104. getservent_r(&serve, servbuf, servbuf_sz, &result);
  105. return result;
  106. }
  107. int getservbyname_r(const char *name, const char *proto,
  108. struct servent *result_buf, char *buf, size_t buflen,
  109. struct servent **result)
  110. {
  111. register char **cp;
  112. int ret;
  113. __UCLIBC_MUTEX_LOCK(mylock);
  114. setservent(serv_stayopen);
  115. while (!(ret = getservent_r(result_buf, buf, buflen, result))) {
  116. if (strcmp(name, result_buf->s_name) == 0)
  117. goto gotname;
  118. for (cp = result_buf->s_aliases; *cp; cp++)
  119. if (strcmp(name, *cp) == 0)
  120. goto gotname;
  121. continue;
  122. gotname:
  123. if (proto == 0 || strcmp(result_buf->s_proto, proto) == 0)
  124. break;
  125. }
  126. if (!serv_stayopen)
  127. endservent();
  128. __UCLIBC_MUTEX_UNLOCK(mylock);
  129. return *result ? 0 : ret;
  130. }
  131. libc_hidden_def(getservbyname_r)
  132. struct servent *getservbyname(const char *name, const char *proto)
  133. {
  134. struct servent *result;
  135. __initbuf();
  136. getservbyname_r(name, proto, &serve, servbuf, servbuf_sz, &result);
  137. return result;
  138. }
  139. int getservbyport_r(int port, const char *proto,
  140. struct servent *result_buf, char *buf,
  141. size_t buflen, struct servent **result)
  142. {
  143. int ret;
  144. __UCLIBC_MUTEX_LOCK(mylock);
  145. setservent(serv_stayopen);
  146. while (!(ret = getservent_r(result_buf, buf, buflen, result))) {
  147. if (result_buf->s_port != port)
  148. continue;
  149. if (proto == 0 || strcmp(result_buf->s_proto, proto) == 0)
  150. break;
  151. }
  152. if (!serv_stayopen)
  153. endservent();
  154. __UCLIBC_MUTEX_UNLOCK(mylock);
  155. return *result ? 0 : ret;
  156. }
  157. libc_hidden_def(getservbyport_r)
  158. struct servent *getservbyport(int port, const char *proto)
  159. {
  160. struct servent *result;
  161. __initbuf();
  162. getservbyport_r(port, proto, &serve, servbuf, servbuf_sz, &result);
  163. return result;
  164. }
  165. libc_hidden_def(getservbyport)