%% options copyright owner = Dirk Krause copyright year = 2011-2014 license = bsd %% module #include "dk3all.h" #include "dkt.h" $!trace-include #if !(DK3_ON_WINDOWS) #if DK3_HAVE_GETPWENT /** Job structure. */ typedef struct { dk3_app_t *app; /**< Application. */ dkChar const * const *msg; /**< Localized messages. */ dkChar const * const *kwnl; /**< Keywords, not localized. */ dk3_option_set_t *opt; /**< Option set. */ unsigned long min; /**< Minimum UID range. */ unsigned long max; /**< Maximum UID range. */ int exval; /**< Exit status code. */ int f_all; /**< Flag: Show all UIDs. */ } DKT_UID_J; /** Data for the option set. */ static dk3_option_t const dkt_uid_options[] = { { dkT('a'), dkT("all"), 0 } }; /** Number of options in the dkt_uid_options array. */ static size_t const dkt_uid_szoptions = sizeof(dkt_uid_options)/sizeof(dk3_option_t); /** Initialize job structure. @param j Job structure. */ static void dkt_uid_job_init(DKT_UID_J *j) { j->app = NULL; j->msg = NULL; j->kwnl = NULL; j->opt = NULL; j->exval = DKT_RESULT_ERR_UNSPECIFIC; j->f_all = 0; j->min = 0UL; j->max = 16384UL; } /** Clean up job structure. @param j Job structure. */ static void dkt_uid_job_cleanup(DKT_UID_J *j) { if(j->opt) { dk3opt_close(j->opt); } j->opt = NULL; } /** Process command line arguments. @param j Job structure. @return 1 on success (can continue), 0 on error (abort). */ static int dkt_uid_process_arguments(DKT_UID_J *j) { int back = 0; int xargc = 0; /* Number of command line arguments. */ int ec = 0; /* Mathematical error code. */ dkChar const *arg = NULL; /* Current argument. */ dkChar const * const *xargv = NULL; /* Command line arguments array. */ xargc = dk3app_get_argc(j->app); xargv = dk3app_get_argv(j->app); xargc --; xargc--; xargv++; xargv++; j->opt = dk3opt_open_app( dkt_uid_options, dkt_uid_szoptions, dkT('\0'), NULL, xargc, xargv, j->app ); if(j->opt) { if(0 == dk3opt_get_error_code(j->opt)) { if(dk3opt_is_set(j->opt, dkT('a'))) { j->f_all = 1; } if(dk3opt_get_num_args(j->opt) > 0) { arg = dk3opt_get_arg(j->opt, 0); if(arg) { #if VERSION_BEFORE_20140716 if(dk3sf_sscanf3(arg, dkT("%lu"), &(j->min)) == 1) #else if (0 != dk3ma_ul_from_string(&(j->min), arg, NULL)) #endif { back = 1; j->max = j->min; if(dk3opt_get_num_args(j->opt) > 1) { back = 0; arg = dk3opt_get_arg(j->opt, 1); if(arg) { #if VERSION_BEFORE_20140716 if(dk3sf_sscanf3(arg, dkT("%lu"), &(j->min)) == 1) #else if (0 != dk3ma_ul_from_string(&(j->min), arg, NULL)) #endif { back = 1; if(j->min > j->max) { unsigned long ul; ul = j->min; j->min = j->max; j->max = ul; } } else { /* ERROR: Not numeric! */ dk3app_log_i3(j->app, DK3_LL_ERROR, 141, 142, arg); j->exval = DKT_RESULT_ERR_OPTION; } } else { /* BUG */ j->exval = DKT_RESULT_ERR_OPTION; } } else { /* Warning: Missing maximum! */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 58); j->exval = DKT_RESULT_ERR_OPTION; } } else { /* ERROR: Not numeric! */ dk3app_log_i3(j->app, DK3_LL_ERROR, 141, 142, arg); j->exval = DKT_RESULT_ERR_OPTION; } } else { /* BUG */ j->exval = DKT_RESULT_ERR_OPTION; } } else { /* ERROR: Missing minimum. */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 59); j->exval = DKT_RESULT_ERR_OPTION; } } else { j->exval = DKT_RESULT_ERR_OPTION; } } else { j->exval = DKT_RESULT_ERR_OPTION; } if(ec) { dk3app_log_i1(j->app, DK3_LL_ERROR, 15); back = 0; } return back; } /** Search for available UIDs. @param j Job structure. */ static void dkt_uid_run(DKT_UID_J *j) { int ec = 0; /* Math error code. */ unsigned long szul = 0UL; /* Difference max - min. */ size_t sz = 0; /* Difference as allocation size. */ dk3_bf_t *bf = NULL; /* Flags for used UIDs. */ struct passwd *pw = NULL; /* Current account to process. */ unsigned long uid = 0UL; /* Current UID. */ int found = 0; /* Flag: At least one UID found. */ int conr = 0; /* Conversion result. */ dkChar bu[64]; /* Buffer for number. */ szul = dk3ma_ul_sub_ok(j->max, j->min, &ec); szul = dk3ma_ul_add_ok(szul, 1UL, &ec); if(ec == 0) { sz = (size_t)szul; #if VERSION_BEFORE_20140809 if((unsigned long)sz == szul) #else if (szul <= (unsigned long)(DK3_SIZE_T_MAX)) #endif { bf = dk3bf_open_app(sz, j->app); if(bf) { #if DK3_HAVE_SETPWENT setpwent(); #endif while((pw = getpwent()) != NULL) { uid = (unsigned long)(pw->pw_uid); if(uid >= j->min) { if(uid <= j->max) { szul = uid - j->min; dk3bf_set(bf, (size_t)szul, 1); } } } #if DK3_HAVE_SETPWENT endpwent(); #endif szul = j->max - j->min + 1UL; sz = 0; while(szul) { if(!dk3bf_get(bf, sz)) { #if VERSION_BEFORE_20140716 dk3sf_sprintf3(bu, dkT("%lu"), (j->min + (unsigned long)sz)); #else conr = dk3ma_um_to_string( bu, DK3_SIZEOF(bu,dkChar), (dk3_um_t)(j->min + (unsigned long)sz) ); if (0 == conr) { bu[0] = dkT('\0'); } #endif dk3sf_fputs(bu, stdout); dk3sf_fputc(dkT('\n'), stdout); found = 1; if(!(j->f_all)) { szul = 1UL; } } szul--; sz++; } dk3bf_close(bf); if(!found) { /* ERROR: No free UID found! */ dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 60); j->exval = DKT_RESULT_ERR_OPTION; } } else { /* ERROR: Memory */ j->exval = DKT_RESULT_ERR_MEMORY; } } else { /* ERROR: Math problem in size calculation. */ j->exval = DKT_RESULT_ERR_MATH_OVERFLOW; dk3app_log_i1(j->app, DK3_LL_ERROR, 15); } } else { /* ERROR: Math problem in size calculation. */ j->exval = DKT_RESULT_ERR_MATH_OVERFLOW; dk3app_log_i1(j->app, DK3_LL_ERROR, 15); } } #endif #endif int dkt_uid( dk3_app_t *app, dkChar const *sn, dkChar const * const *msg, dkChar const * const *kwnl ) { int back = DKT_RESULT_ERR_UNSPECIFIC; #if DK3_ON_WINDOWS dk3app_log_1(app, DK3_LL_ERROR, msg, 57); return DKT_RESULT_ERR_UNSUPPORTED; #else #if DK3_HAVE_GETPWENT DKT_UID_J j; $? "+ dkt_uid" dkt_uid_job_init(&j); j.app = app; j.msg = msg; j.kwnl = kwnl; if(dkt_uid_process_arguments(&j)) { j.exval = DKT_RESULT_OK; dkt_uid_run(&j); } back = j.exval; dkt_uid_job_cleanup(&j); $? "- dkt_uid %d", back #else dk3app_log_1(app, DK3_LL_ERROR, msg, 56); return DKT_RESULT_ERR_UNSUPPORTED; #endif #endif return back; } /* vim: set ai sw=2 : */