/
niceSOFT
/
inetutils
Обзор
Документация
Войти
/
niceSOFT
/
inetutils
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
v2.2
src/hostname.c
425 строк
10 KB
Alfred M. Szmidt
Happy GNU 2021 year!
01 янв 2021, 13:35
01 янв 2021, 13:35
911413e
Код
Авторство
О чём код?
/* Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Free Software Foundation, Inc. This file is part of GNU Inetutils. GNU Inetutils is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNU Inetutils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see `http://www.gnu.org/licenses/'. */ #include <config.h> #include <argp.h> #include <error.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <netinet/in.h> #include <arpa/inet.h> #include <progname.h> #include "libinetutils.h" #include "xalloc.h" #include "xgethostname.h" #include "xgetdomainname.h" typedef struct { const char *hostname_file; char *hostname_new; short int hostname_alias; short int hostname_fqdn; short int hostname_ip_address; short int hostname_dns_domain; short int hostname_short; } hostname_arguments; static char *(*get_name_action) (void) = NULL; static int (*set_name_action) (const char *name, size_t size) = NULL; const char args_doc[] = "[NAME]"; const char doc[] = "Show or set the system's host name."; const char *program_authors[] = { "Debarshi Ray", NULL }; static struct argp_option argp_options[] = { #define GRP 0 {"aliases", 'a', NULL, 0, "alias names", GRP+1}, {"domain", 'd', NULL, 0, "DNS domain name", GRP+1}, {"file", 'F', "FILE", 0, "set host name or NIS domain name from FILE", GRP+1}, {"fqdn", 'f', NULL, 0, "DNS host name or FQDN", GRP+1}, {"long", 'f', NULL, OPTION_ALIAS, "DNS host name or FQDN", GRP+1}, {"ip-addresses", 'i', NULL, 0, "addresses for the host name", GRP+1}, {"short", 's', NULL, 0, "short host name", GRP+1}, {"yp", 'y', NULL, 0, "NIS/YP domain name", GRP+1}, {"nis", 0, NULL, OPTION_ALIAS, NULL, GRP+1}, #undef GRP {NULL, 0, NULL, 0, NULL, 0} }; static error_t parse_opt (int key, char *arg, struct argp_state *state) { hostname_arguments *const args = (hostname_arguments *const) state->input; switch (key) { case 'a': get_name_action = xgethostname; args->hostname_alias = 1; break; case 'd': get_name_action = xgethostname; args->hostname_fqdn = 1; args->hostname_dns_domain = 1; break; case 'F': set_name_action = (void *) sethostname; args->hostname_file = arg; break; case 'f': get_name_action = xgethostname; args->hostname_fqdn = 1; break; case 'i': get_name_action = xgethostname; args->hostname_ip_address = 1; break; case 's': get_name_action = xgethostname; args->hostname_fqdn = 1; args->hostname_short = 1; break; case 'y': get_name_action = xgetdomainname; break; case ARGP_KEY_ARG: set_name_action = (void *) sethostname; args->hostname_new = strdup (arg); if (args->hostname_new == NULL) error (EXIT_FAILURE, errno, "strdup"); break; default: return ARGP_ERR_UNKNOWN; } return 0; } static struct argp argp = {argp_options, parse_opt, args_doc, doc, NULL, NULL, NULL}; static void get_name (const hostname_arguments *const args); static void set_name (const hostname_arguments *const args); static char * get_aliases (const char *const host_name); static char * get_fqdn (const char *const host_name); static char * get_ip_addresses (const char *const host_name); static char * get_dns_domain_name (const char *const host_name); static char * get_short_hostname (const char *const host_name); static char * parse_file (const char *const file_name); int main (int argc, char *argv[]) { hostname_arguments args; set_program_name (argv[0]); memset ((void *) &args, 0, sizeof (args)); /* Parse command line */ iu_argp_init ("hostname", program_authors); argp_parse (&argp, argc, argv, 0, NULL, (void *) &args); /* Set default action */ if (get_name_action == NULL && set_name_action == NULL) get_name_action = xgethostname; if (get_name_action == xgetdomainname || get_name_action == xgethostname) get_name (&args); else if ((void *) set_name_action == (void *) sethostname) set_name (&args); return 0; } static void get_name (const hostname_arguments *const args) { char *sname, *name; sname = (*get_name_action) (); if (!sname) error (EXIT_FAILURE, errno, "cannot determine name"); if (args->hostname_alias == 1) name = get_aliases (sname); else if (args->hostname_fqdn == 1) { name = get_fqdn (sname); if (args->hostname_dns_domain == 1 || args->hostname_short == 1) { /* Eliminate empty replies, as well as `(none)'. */ if (name && *name && *name != '(') { free (sname); sname = name; name = NULL; } else if (name && *name == '(') { free (name); name = NULL; } } if (args->hostname_dns_domain == 1) name = get_dns_domain_name (sname); else if (args->hostname_short == 1) name = get_short_hostname (sname); } else if (args->hostname_ip_address == 1) name = get_ip_addresses (sname); else { name = strdup (sname); if (name == NULL) error (EXIT_FAILURE, errno, "strdup"); } if (name && *name) puts (name); free (name); free (sname); return; } static void set_name (const hostname_arguments *const args) { char *hostname_new; int status; size_t size; if (args->hostname_file != NULL) hostname_new = parse_file (args->hostname_file); else hostname_new = args->hostname_new; size = hostname_new ? strlen (hostname_new) : 0; if (!size) error (EXIT_FAILURE, 0, "Empty hostname"); status = (*set_name_action) (hostname_new, size); if (status == -1) error (EXIT_FAILURE, errno, "sethostname"); free (hostname_new); return; } static char * get_aliases (const char *const host_name) { char *aliases; unsigned int count = 0; unsigned int i; unsigned int size = 256; struct hostent *ht; aliases = xmalloc (sizeof (char) * size); aliases[0] = '\0'; ht = gethostbyname (host_name); if (ht == NULL) strcpy (aliases, ""); /* Be honest about missing aliases. */ else { for (i = 0; ht->h_aliases[i] != NULL; i++) { /* Aliases should be blankspace separated. */ if (ht->h_aliases[i+1] != NULL) count++; count += strlen (ht->h_aliases[i]); if (count >= size) { size *= 2; aliases = xrealloc (aliases, size); } strcat (aliases, ht->h_aliases[i]); strcat (aliases, " "); } } return aliases; } static char * get_fqdn (const char *const host_name) { char *fqdn; struct hostent *ht; ht = gethostbyname (host_name); if (ht == NULL) fqdn = strdup (host_name); /* Fall back to system name. */ else fqdn = strdup (ht->h_name); if (fqdn == NULL) error (EXIT_FAILURE, errno, "strdup"); return fqdn; } static char * get_ip_addresses (const char *const host_name) { char address[16]; char *addresses; unsigned int count = 0; unsigned int i; unsigned int size = 256; struct hostent *ht; addresses = xmalloc (sizeof (char) * size); addresses[0] = '\0'; ht = gethostbyname (host_name); if (ht == NULL) #if HAVE_HSTRERROR error (EXIT_FAILURE, 0, "gethostbyname: %s", hstrerror (h_errno)); #else strcpy (addresses, "(none)"); #endif else { for (i = 0; ht->h_addr_list[i] != NULL; i++) { inet_ntop (ht->h_addrtype, (void *) ht->h_addr_list[i], address, sizeof (address)); /* IP addresses should be blankspace separated. */ if (ht->h_addr_list[i+1] != NULL) count++; count += strlen (address); if (count >= size) { size *= 2; addresses = xrealloc (addresses, size); } strcat (addresses, address); /* Insert a separating space character. */ if (ht->h_addr_list[i+1] != NULL) strcat (addresses, " "); } } return addresses; } static char * get_dns_domain_name (const char *const host_name) { char *domain_name; const char * pos; pos = strchr (host_name, '.'); if (pos == NULL) domain_name = strdup ("(none)"); else domain_name = strdup (pos+1); if (domain_name == NULL) error (EXIT_FAILURE, errno, "strdup"); return domain_name; } static char * get_short_hostname (const char *const host_name) { size_t size; char *short_hostname; const char * pos; pos = strchr (host_name, '.'); if (pos == NULL) short_hostname = strdup (host_name); else { size = pos - host_name; short_hostname = strndup (host_name, size); } if (short_hostname == NULL) error (EXIT_FAILURE, errno, "strdup"); return short_hostname; } static char * parse_file (const char *const file_name) { char *buffer = NULL; char *name = NULL; FILE *file; ssize_t nread; size_t size = 0; file = fopen (file_name, "r"); if (file == NULL) error (EXIT_FAILURE, errno, "fopen"); errno = 0; /* Portability issue! */ do { nread = getline (&buffer, &size, file); if (nread == -1) error (EXIT_FAILURE, errno, "getline%s", errno ? "" : ": No text"); if (buffer[0] != '#') { name = (char *) xmalloc (sizeof (char) * (nread + 1)); if (sscanf (buffer, "%s", name) == 1) break; free (name); name = NULL; } } while (feof (file) == 0); free (buffer); fclose (file); return name; }