嵌入式成长轨迹24【Linux应用编程强化】【Linux下的C编程 下】【实例:Linux命令实现】
一 功能与参数介绍
id [-gGnru] [--help] [--version] [用户名称]
各参数的具体含义如下所示:
-g或-group:显示有效用户组ID。
-G或-groups:显示辅助用户组ID;
-n或-name:显示名称,而不是ID;
-r或-real:显示实际用户ID;
-u或-user:显示有效用户ID;
-help:显示帮助信息;
-version:显示版本信息。
二 主函数代码精要
1、
enum
{
GETOPT_HELP_CHAR = (CHAR_MIN - 2),
GETOPT_VERSION_CHAR = (CHAR_MIN - 3)
};
#define EXIT_FAILURE 1
#define EXIT_SUCCESS 0
2、
#include <system.h>
#define HELP_OPTION_DESCRIPTION \
_(" --help display this help and exit\n")
#define VERSION_OPTION_DESCRIPTION \
_(" --version output version information and exit\n")
#include <system.h>
#define _(msgid) gettext (msgid)
#define N_(msgid) msgid
3、
#include <gettext.h>
# define gettext(Msgid) ((const char *) (Msgid))
initialize_main (&argc, &argv);
#include <system.h>
#ifndef initialize_main
# define initialize_main(ac, av)
#endif
4、
#include <locale.h>
char *setlocale (int category, const char *locale)
LC_COLLATE:表示设定排列顺序
LC_CTYPE:字符分类和转换,例如将所有的字符转换成小写或大写形式
LC_MESSAGES:系统信息的格式
LC_MONETARY:货币的格式
LC_NUMERIC:数值的格式
LC_TIME:日期和时间的格式
LC_ALL:设置上述所有的选项
setlocale (LC_ALL, NULL);
5、
#include <system.h>
#if ! ENABLE_NLS
# undef textdomain
# define textdomain(Domainname)
# undef bindtextdomain
# define bindtextdomain(Domainname, Dirname)
#endif
6、
int atexit (void (*)(void));
int getopt_long(int argc, char * const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
7、
#include <system.h>
enum
{
GETOPT_HELP_CHAR = (CHAR_MIN - 2),
GETOPT_VERSION_CHAR = (CHAR_MIN - 3)
};
#define case_GETOPT_HELP_CHAR \
case GETOPT_HELP_CHAR: \
usage (EXIT_SUCCESS); \
break;
#define case_GETOPT_VERSION_CHAR(Program_name, Authors) \
case GETOPT_VERSION_CHAR: \
version_etc (stdout, Program_name, GNU_PACKAGE, VERSION, Authors, \
(char *) NULL); \
exit (EXIT_SUCCESS); \
break;
三 其他函数代码
接下来主要为一些相关支持函数的定义,包括print_user、print_group、xgetgroups、print_group_list、以及print_full_info等。
四小结
阅读Coreutils中id命令的源代码,它是Linux系统中实际应用的程序,代码是稳定、高效、经过严格测试过的。程序中的很多地方,尤其是宏的使用、出错处理等部分,是非常值得用户学习和借鉴的。
1 /* id -- print real and effective UIDs and GIDs 2 3 Copyright (C) 1989-2005 Free Software Foundation, Inc. 4 5 6 7 This program is free software; you can redistribute it and/or modify 8 9 it under the terms of the GNU General Public License as published by 10 11 the Free Software Foundation; either version 2, or (at your option) 12 13 any later version. 14 15 16 17 This program is distributed in the hope that it will be useful, 18 19 but WITHOUT ANY WARRANTY; without even the implied warranty of 20 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 23 GNU General Public License for more details. 24 25 26 27 You should have received a copy of the GNU General Public License 28 29 along with this program; if not, write to the Free Software Foundation, 30 31 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 32 33 34 35 /* Written by Arnold Robbins. 36 37 Major rewrite by David MacKenzie, djm@gnu.ai.mit.edu. */ 38 39 40 41 #include <config.h> 42 43 #include <stdio.h> 44 45 #include <getopt.h> 46 47 #include <sys/types.h> 48 49 #include <pwd.h> 50 51 #include <grp.h> 52 53 #include <getopt.h> 54 55 56 57 #include "system.h" 58 59 #include "error.h" 60 61 #include "quote.h" 62 63 #define PROGRAM_NAME "id" 64 65 #define AUTHORS "Arnold Robbins", "David MacKenzie" 66 67 int getugroups (); 68 69 70 71 static void print_user (uid_t uid); 72 73 static void print_group (gid_t gid); 74 75 static void print_group_list (const char *username); 76 77 static void print_full_info (const char *username); 78 79 char *program_name; /* 程序名 */ 80 81 static bool use_name = false; /* 如果设为true,输出用户或组的名称,而不是ID,对应于-n选项 */ 82 83 static uid_t ruid, euid; /* 用户的实际ID和有效ID */ 84 85 static gid_t rgid, egid; /* 用户组的实际ID和有效ID */ 86 87 static bool ok = true; /* 如果发生错误,将该变量设为ture */ 88 89 static struct option const longopts[] = 90 91 { 92 93 {"group", no_argument, NULL, 'g'}, 94 95 {"groups", no_argument, NULL, 'G'}, 96 97 {"name", no_argument, NULL, 'n'}, 98 99 {"real", no_argument, NULL, 'r'}, 100 101 {"user", no_argument, NULL, 'u'}, 102 103 {GETOPT_HELP_OPTION_DECL}, 104 105 {GETOPT_VERSION_OPTION_DECL}, 106 107 {NULL, 0, NULL, 0} 108 109 }; 110 111 void 112 113 usage (int status) 114 115 { 116 117 if (status != EXIT_SUCCESS) 118 119 fprintf (stderr, _("Try `%s --help' for more information.\n"), 120 121 program_name); 122 123 else 124 125 { 126 127 printf (_("Usage: %s [OPTION]... [USERNAME]\n"), program_name); 128 129 fputs (_("\ 130 131 Print information for USERNAME, or the current user.\n\ 132 133 \n\ 134 135 -a ignore, for compatibility with other versions\n\ 136 137 -g, --group print only the effective group ID\n\ 138 139 -G, --groups print all group IDs\n\ 140 141 -n, --name print a name instead of a number, for -ugG\n\ 142 143 -r, --real print the real ID instead of the effective ID, with -ugG\n\ 144 145 -u, --user print only the effective user ID\n\ 146 147 "), stdout); 148 149 fputs (HELP_OPTION_DESCRIPTION, stdout); 150 151 fputs (VERSION_OPTION_DESCRIPTION, stdout); 152 153 fputs (_("\ 154 155 \n\ 156 157 Without any OPTION, print some useful set of identified information.\n\ 158 159 "), stdout); 160 161 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); 162 163 } 164 165 exit (status); 166 167 } 168 169 int 170 171 main (int argc, char **argv) 172 173 { 174 175 int optc; 176 177 178 179 bool just_group_list = false; /* 如果设为true,输出所有用户组ID列表,对应于-G选项 */ 180 181 bool just_group = false; /* 如果设为true,输出用户组ID,对应于-g选项 */ 182 183 bool use_real = false; /* 如果设为true,输出实际用户ID和组ID,默认情况下输出 */ 184 185 /* 有效用户ID和组ID,对应于-r选项 */ 186 187 bool just_user = false; /* 如果设为true,输出实际用户ID,对应于-u选项*/ 188 189 program_name = argv[0]; /* 程序名 */ 190 191 setlocale (LC_ALL, ""); 192 193 bindtextdomain (PACKAGE, LOCALEDIR); 194 195 textdomain (PACKAGE); 196 197 atexit (close_stdout); 198 199 while ((optc = getopt_long (argc, argv, "agnruG", longopts, NULL)) != -1) /* 分析命令行参数 */ 200 201 { 202 203 switch (optc) 204 205 { 206 207 case 'a': /*忽略-a选项,主要是出于SVR4(UNIX System V Release4)兼容性的考虑 */ 208 209 210 211 break; 212 213 case 'g': /* -g选项,将变量just_group设为true */ 214 215 just_group = true; 216 217 break; 218 219 case 'n': /* -n选项,将变量use_name设为true */ 220 221 use_name = true; 222 223 break; 224 225 case 'r': /* -r选项,将变量use_real设为true */ 226 227 use_real = true; 228 229 break; 230 231 case 'u': /* -u选项,将变量just_user设为true */ 232 233 just_user = true; 234 235 break; 236 237 case 'G': /* -G选项,将变量just_group_list设为true */ 238 239 just_group_list = true; 240 241 break; 242 243 case_GETOPT_HELP_CHAR; 244 245 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); 246 247 default: 248 249 usage (EXIT_FAILURE); 250 251 } 252 253 } 254 255 if (just_user + just_group + just_group_list > 1) 256 257 error (EXIT_FAILURE, 0, _("cannot print only user and only group")); 258 259 260 261 if (just_user + just_group + just_group_list == 0 && (use_real | use_name)) 262 263 error (EXIT_FAILURE, 0, 264 265 _("cannot print only names or real IDs in default format")); 266 267 268 269 if (argc - optind > 1) 270 271 { 272 273 error (0, 0, _("extra operand %s"), quote (argv[optind + 1])); 274 275 usage (EXIT_FAILURE); 276 277 } 278 279 if (argc - optind == 1) 280 281 { 282 283 struct passwd *pwd = getpwnam (argv[optind]); /* 获取指定用户的账号信息 */ 284 285 if (pwd == NULL) 286 287 error (EXIT_FAILURE, 0, _("%s: No such user"), argv[optind]); 288 289 ruid = euid = pwd->pw_uid; 290 291 rgid = egid = pwd->pw_gid; 292 293 } 294 295 else 296 297 { 298 299 euid = geteuid (); /* 获取有效用户ID */ 300 301 ruid = getuid (); /* 获取实际用户ID */ 302 303 egid = getegid (); /* 获取有效组ID */ 304 305 rgid = getgid (); /* 获取实际组ID */ 306 307 } 308 309 if (just_user) 310 311 print_user (use_real ? ruid : euid); 312 313 else if (just_group) 314 315 print_group (use_real ? rgid : egid); 316 317 else if (just_group_list) 318 319 print_group_list (argv[optind]); 320 321 else 322 323 print_full_info (argv[optind]); 324 325 putchar ('\n'); 326 327 exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); 328 329 } 330 331 static void 332 333 print_user (uid_t uid) 334 335 { 336 337 struct passwd *pwd = NULL; /* 定义指向passwd结构的指针 */ 338 339 340 341 if (use_name) 342 343 { 344 345 pwd = getpwuid (uid); /* 从密码文件中获取指定uid的数据 */ 346 347 if (pwd == NULL) /* 如果数据获取失败,输出错误信息,并将变量ok设为false */ 348 349 { 350 351 error (0, 0, _("cannot find name for user ID %lu"), 352 353 (unsigned long int) uid); 354 355 ok = false; 356 357 } 358 359 } 360 361 362 363 if (pwd == NULL) 364 365 printf ("%lu", (unsigned long int) uid); /* 输出用户ID */ 366 367 else 368 369 printf ("%s", pwd->pw_name); /* 输出用户名称 */ 370 371 } 372 373 static void 374 375 print_group (gid_t gid) 376 377 { 378 379 struct group *grp = NULL; /* 定义指向group结构的指针 */ 380 381 382 383 if (use_name) 384 385 { 386 387 grp = getgrgid (gid); /* 从组文件中获取指定gid的数据 */ 388 389 if (grp == NULL) /* 如果数据获取失败,输出错误信息,并将变量ok设为false */ 390 391 { 392 393 error (0, 0, _("cannot find name for group ID %lu"), 394 395 (unsigned long int) gid); 396 397 ok = false; 398 399 } 400 401 } 402 403 404 405 if (grp == NULL) 406 407 printf ("%lu", (unsigned long int) gid); /* 输出用户组ID */ 408 409 else 410 411 printf ("%s", grp->gr_name); /* 输出用户组名称 */ 412 413 } 414 415 static bool 416 417 xgetgroups (const char *username, gid_t gid, int *n_groups, 418 419 GETGROUPS_T **groups) 420 421 { 422 423 int max_n_groups; 424 425 int ng; 426 427 GETGROUPS_T *g = NULL; 428 429 /* 调用getgroups或getugroups函数获取用户所属的组数,并保存到变量max_n_groups之中 */ 430 431 if (!username) 432 433 max_n_groups = getgroups (0, NULL); 434 435 else 436 437 max_n_groups = getugroups (0, NULL, username, gid); 438 439 440 441 if (max_n_groups < 0) 442 443 ng = -1; 444 445 else 446 447 { 448 449 g = xnmalloc (max_n_groups, sizeof *g); /* 根据组数分配内存空间 */ 450 451 if (!username) 452 453 ng = getgroups (max_n_groups, g); /* 获取用户所属的组ID,报讯到 */ 454 455 else 456 457 ng = getugroups (max_n_groups, g, username, gid); 458 459 } 460 461 /* 根据ng的取值,完成函数返回前的相关处理工作,例如释放内存空间,返回组数、组ID等 */ 462 463 if (ng < 0) 464 465 { 466 467 error (0, errno, _("cannot get supplemental group list")); 468 469 free (g); 470 471 return false; 472 473 } 474 475 else 476 477 { 478 479 *n_groups = ng; 480 481 *groups = g; 482 483 return true; 484 485 } 486 487 } 488 489 static void 490 491 print_group_list (const char *username) /* 输入参数为用户名 */ 492 493 { 494 495 struct passwd *pwd; /* 定义指向passwd结构的指针 */ 496 497 498 499 pwd = getpwuid (ruid); /* 从密码文件中获取指定uid的数据 */ 500 501 if (pwd == NULL) /* 如果数据获取失败,并将变量ok设为false */ 502 503 ok = false; 504 505 506 507 print_group (rgid); /* 输出实际组ID或组名 */ 508 509 if (egid != rgid) /* 判断有效组ID与实际组ID是否相同 */ 510 511 { 512 513 putchar (' '); 514 515 print_group (egid); /* 输出有效组ID或组名 */ 516 517 } 518 519 int n_groups; 520 521 GETGROUPS_T *groups; 522 523 int i; 524 525 /* 调用xgetgroups函数获取用户所属组的数目和组ID,并处理函数的返回结果 */ 526 527 if (! xgetgroups (username, (pwd ? pwd->pw_gid : (gid_t) -1), 528 529 &n_groups, &groups)) 530 531 { 532 533 ok = false; 534 535 return; 536 537 } 538 539 /* 输出用户所有的附加组ID或名称 */ 540 541 for (i = 0; i < n_groups; i++) 542 543 if (groups[i] != rgid && groups[i] != egid) /* 判断是否为实际用户组ID和有效用户组ID */ 544 545 { 546 547 putchar (' '); 548 549 print_group (groups[i]); 550 551 } 552 553 free (groups); 554 555 } 556 557 t_group_list函数的功能是输出用户所属附加组的标识符或名称。 558 559 static void 560 561 print_full_info (const char *username) 562 563 { 564 565 struct passwd *pwd; /* 定义指向passwd结构的指针 */ 566 567 struct group *grp; /* 定义指向group结构的指针 */ 568 569 570 571 printf ("uid=%lu", (unsigned long int) ruid); /* 输出实际用户ID */ 572 573 pwd = getpwuid (ruid); /* 获取实际用户的信息 */ 574 575 if (pwd) 576 577 printf ("(%s)", pwd->pw_name); /* 输出实际用户的名称 */ 578 579 580 581 printf (" gid=%lu", (unsigned long int) rgid); /* 输出实际用户组ID */ 582 583 grp = getgrgid (rgid); /* 获取实际用户组的信息 */ 584 585 if (grp) 586 587 printf ("(%s)", grp->gr_name); /* 输出实际用户组的名称 */ 588 589 /* 如果有效用户ID与实际用户ID不同,输出有效用户ID与名称 */ 590 591 if (euid != ruid) 592 593 { 594 595 printf (" euid=%lu", (unsigned long int) euid); 596 597 pwd = getpwuid (euid); 598 599 if (pwd) 600 601 printf ("(%s)", pwd->pw_name); 602 603 } 604 605 /* 如果有效用户组ID与实际用户组ID不同,输出有效用户组ID与名称 */ 606 607 if (egid != rgid) 608 609 { 610 611 printf (" egid=%lu", (unsigned long int) egid); 612 613 grp = getgrgid (egid); 614 615 if (grp) 616 617 printf ("(%s)", grp->gr_name); 618 619 } 620 621 622 623 int n_groups; 624 625 GETGROUPS_T *groups; 626 627 int i; 628 629 /* 输出用户所有的附加组ID */ 630 631 if (! xgetgroups (username, (pwd ? pwd->pw_gid : (gid_t) -1), 632 633 &n_groups, &groups)) 634 635 { 636 637 ok = false; 638 639 return; 640 641 } 642 643 /* 输出用户所有的附加组名称 */ 644 645 if (n_groups > 0) 646 647 fputs (_(" groups="), stdout); 648 649 for (i = 0; i < n_groups; i++) 650 651 { 652 653 if (i > 0) 654 655 putchar (','); 656 657 printf ("%lu", (unsigned long int) groups[i]); 658 659 grp = getgrgid (groups[i]); 660 661 if (grp) 662 663 printf ("(%s)", grp->gr_name); 664 665 } 666 667 free (groups); 668 669 }