2017-05-03 1 views
-2

Pour mon informatique à l'école, je dois créer un programme qui génère l'identifiant de l'utilisateur et l'identifiant du groupe d'utilisateurs, tout comme la commande "id", sans les groupes. Cela fonctionne très bien pour moi, mais maintenant je dois utiliser la méthode getpwnam pour faire une version étendue de celui-ci: il devrait être utilisé comme ./id_extended USERNAME, et il devrait sortir l'uid et le GID de cet utilisateur alors. J'ai pris une vue de getpwnam (3), parce que la leçon m'a dit de regarder là pour le faire. Maintenant, il y a un exemple d'utilisation de getpwnam_r avec buffer etc, mais ce n'est pas comme ça que nous devrions le faire; nous devons utiliser le getpwnam simple.C méthode id et getpwnam (3)

Je sais que getpwnam renvoie un pointeur, mais comment ce pointeur peut-il être utilisé pour l'ID du groupe d'utilisateurs et l'ID utilisateur?

+2

Il n'y a pas grand-chose, 'getpwnam' renvoie un pointeur vers une structure avec les données dont vous avez besoin, la [man page] (https://linux.die.net/man/3/getpwnam) décrit la structure. Peut-être pourriez-vous poster ce que vous avez essayé, s'il y a un problème spécifique? – ilkkachu

+0

Bienvenue dans Stack Overflow. Veuillez lire les pages [A propos de] et [Demander] bientôt. Vous devez lire la spécification de ['getpwnam()'] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwnam.html) ou les pages man sur votre machine. C'est simple; la structure contient la plupart des informations dont vous avez besoin, mais vous devrez probablement associer un identifiant de groupe à un nom de groupe (['getgrgid()'] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/ getgrgid.html)). –

+0

oui, je vais bientôt, mais ce problème ne pouvait pas attendre, je suis désolé:/ – xLeevo

Répondre

0

OP aurait dû inclure son code dans la question. Examinons-le en détail:

#include <pwd.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 

Parce que ce code est POSIX.1 C, le code doit commencer par exemple #define _POSIX_C_SOURCE 200809L pour indiquer aux fichiers d'en-tête de la bibliothèque C que nous souhaitons des fonctionnalités POSIX.1-2008.

getpwnam() nécessite #include <pwd.h> mais également #include <sys/types.h>, qui n'est pas répertorié. Si elle est utilisée, getuid() et getgid() nécessitent #include <unistd.h>, qui est répertorié.

L'E/S standard requiert #include <stdio.h> et #include <errno.h> fournit errno et les codes d'erreur. Personnellement, je aussi #include <string.h> pour strerror(), parce que j'aime utiliser fprintf() pour imprimer des messages d'erreur dans mon propre format (plutôt que d'utiliser par exemple perror() de <stdio.h>, ou la %m extension GNU.

La partie suivante,

struct passwd *getpwnam(const char *name); 
uid_t getuid(void); 
uid_t geteuid(void); 
struct passwd pass; 

est assez problématique: Tout d'abord, vous n'avez pas besoin de déclarer les fonctions de la bibliothèque C, les fichiers d'en-tête les déclarent déjà pour nous, la valeur de retour de getpwnam() est un pointeur vers struct passwd - c'est ce que signifie struct passwd *! -, déclarant ainsi struct passwd pass n'a aucun sens. Troisièmement, si pass n'est utilisé que dans main(), il doit être déclaré en tant que variable locale dans main(), et non en tant que variable globale (en dehors de toute fonction).

Dans la dernière partie,

int main(int argc,char* argv[]) { 
    if(argc == 1){ 
    printf("user: %d\ngroup: %d\n",getuid(),getgid()); 
    } 
    if(argc == 2){ 
    pass = getpwnam(argv[1]); 
    printf("%s %ld",pass.pw_uid,pass.pw_gid); 
    } 
} 

nous voyons que main() est défini (comme la prise int argc et char *argv[]) correctement; Cependant, il n'y a pas de déclaration return (some int) exigée par la déclaration. Ceci est mieux fixé en ajoutant un return EXIT_SUCCESS; à la fin.

Depuis pass est seulement utilisé dans main(), il devrait être une variable locale, et donc le corps de main() devrait commencer par sa déclaration correcte: struct passwd *pass;.

Le programme ne fait rien si vous fournissez deux arguments ou plus. C'est très surprenant et pas souhaitable.Un if (argc == 1) { /* no arguments */ } else if (argc == 2) { /* one argument */ } else { /* two or more arguments */ } avec un message d'erreur imprimé dans le cas de trop d'arguments serait un choix beaucoup plus judicieux ici.

Dans un cas, l'argument (argc == 2 - rappelez-vous que argc comprend argv[0], qui est le nom utilisé pour exécuter ce programme), il y a deux problèmes distincts: Tout d'abord, pass n'est pas un pointeur (qui peut être fixé en déclarant comme indiqué ci-dessus). Deuxièmement, et le point le plus important, est qu'il n'y a pas de vérification si getpwnam() a réussi ou échoué.

En cas d'erreur, man 3 getpwnam nous dit que getpwnam() retournera NULL si une erreur se produit, avec errno décrivant l'erreur. Cela signifie que si pass est correctement déclaré, vous devez utiliser par exemple.

pass = getpwnam(argv[1]); 
    if (!pass) { 
     fprintf(stderr, "%s: %s.\n", argv[1], strerror(errno)); 
     return EXIT_FAILURE; 
    } 

    /* pass->pw_uid has user ID, 
     pass->pw_gid has group ID, 
     pass->pw_name has user name, 
     and so on. */ 

Notez que if (!pass) est équivalent à if (pass == NULL) POSIX.1 C.

(En utilisant la forme plus courte est juste ma préférence personnelle. Parce que ! est le pas opérateur, j'ai lu la première comme «s'il n'y a pas pass »;.. alors que je lis le second comme « si pass est NULL » le premier est tout simplement plus facile/plus rapide/plus confortable pour moi)

Notez également qu'il n'existe pas de spécificateur de format printf pour uid_t ou gid_t. Alors que la plupart du code utilise int (%d) et suppose que le compilateur gérera la promotion correctement, je préfère personnellement utiliser long (%ld) et transtyper le résultat en long explicitement; par exemple,

printf("uid=%ld (%s)\n", (long)(pass->pw_uid), pass->pw_name); 

(Le plus souvent vous voyez le casting écrit (long)pass->pw_uid, mais à moins que vous vous souvenez des règles de priorité de l'opérateur en C désinvolture, il peut ne pas être évident qui partie de l'expression est jeté à long. Pour que les humains lisent explicitement le code - le compilateur ne s'en soucie pas du tout! -, je l'écris de temps en temps sous la forme (long)(pass->pw_uid), car l'objet de la distribution est alors évidemment (pass->pw_uid), soit la valeur du champ pw_uid dans la structure pointé par pass.)

Fi En fait, il y a deux changements dans la logique du programme que j'aimerais suggérer. Au lieu d'utiliser le struct passwd *pass si un nom d'utilisateur était spécifié, je l'utiliserais également si aucun nom d'utilisateur n'est spécifié, pour obtenir les informations utilisateur en cours en utilisant getpwuid(getuid()). Ensuite, le code qui imprime les informations dans la structure pointée par pass, pourrait rester en dehors des corps des clauses if (argc == ..). De cette façon, il n'y a qu'un seul printf() pour imprimer les informations, et ce sera toujours le même formulaire, que l'information soit imprimée pour l'utilisateur actuel ou pour un autre utilisateur spécifié par son nom.

(getuid() et getgid() sont toujours réussi à POSIX.1, ils ne peuvent pas échouer C'est pourquoi il est tout à fait correct de les utiliser sans aucune vérification des erreurs comme ça..)

Le deuxième changement est plus comme une addition .Vous pouvez utiliser getgrgid(pass->pw_uid) ou getgrgid(getgid()) pour obtenir un pointeur vers un struct group qui fournit des informations similaires sur le groupe d'utilisateurs; en particulier ->gr_name, qui est le nom du groupe. Pour utiliser getgrgid(), vous devez également indiquer #include <grp.h> vers le début du fichier. (Elle exige également #include <sys/types.h>, mais vous devriez déjà avoir que, depuis getpwnam() et getpwuid() ont besoin.)

Les informations ci-dessus doit être suffisante pour écrire un programme entièrement travail en fonction des besoins exprimés. Cependant, je ne listerai pas le programme fixe/modifié complet, parce que vous en apprendrez plus et que vous aurez la satisfaction de compléter votre propre travail - et nous évitons tous d'aider les pigeons à exploiter nos efforts en soumettant notre travail comme leur posséder.